<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Blog | Philipp Rieber</title>
    <description>Philipp Rieber's blog</description>
    <link>http://blog.philipp-rieber.net/</link>
    <atom:link href="http://blog.philipp-rieber.net/feed.xml" rel="self" type="application/rss+xml" />
    <pubDate>Wed, 16 Nov 2022 21:30:49 +0000</pubDate>
    <lastBuildDate>Wed, 16 Nov 2022 21:30:49 +0000</lastBuildDate>
    <generator>Jekyll v3.9.2</generator>
    
      <item>
        <title>Creating a PSR-7 Guzzle Request object with form-data</title>
        <description>&lt;p&gt;Uploading files with &lt;a href=&quot;http://docs.guzzlephp.org/en/v6/&quot;&gt;Guzzle 6&lt;/a&gt; using a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;multipart/form-data&lt;/code&gt; request is pretty straightforward. But creating a request object with a file upload independently from the actual sending process turns out to not be that obvious.&lt;/p&gt;

&lt;p&gt;When wrapping everything within one step, performing a file upload with Guzzle 6 using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;multipart/form-data&lt;/code&gt; is as simple as:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&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;GuzzleHttp\Client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&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;Client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$client&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;'POST'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
    &lt;span class=&quot;s1&quot;&gt;'https://xyz.acme.dev/api/upload'&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;'multipart'&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;p&quot;&gt;[&lt;/span&gt;
                &lt;span class=&quot;s1&quot;&gt;'name'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'upload_file'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;s1&quot;&gt;'contents'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;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;'path/to/file'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'r'&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;// ... more fields&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;/div&gt;&lt;/div&gt;

&lt;p&gt;But recently I stumbled upon the requirement to create the request object decoupled from actually sending it with the client. Having only a simple string payload in the message body sending as a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;POST&lt;/code&gt; request would still be quite easy:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&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;GuzzleHttp\Psr7\Request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$payload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'My payload'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$request&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;Request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;'POST'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
    &lt;span class=&quot;s1&quot;&gt;'https://xyz.acme.dev/api/upload'&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;$payload&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$client&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;But how to a create &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;multipart/form-data&lt;/code&gt; payload? Because files can get huge they need to be fed into the request by a stream. Guzzle provides &lt;a href=&quot;http://docs.guzzlephp.org/en/v6/psr7.html#streams&quot;&gt;a lot of different stream types&lt;/a&gt;. Unfortunately the one we need is currently not linked from the docs, but you can find it in the supporting &lt;a href=&quot;https://github.com/guzzle/psr7#multipartstream&quot;&gt;guzzle/psr7&lt;/a&gt; library. Using a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MultipartStream&lt;/code&gt;, the request object can now be created decoupled from the client:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&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;GuzzleHttp\Psr7\Request&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;GuzzleHttp\Psr7\MultipartStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$multipart&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;MultipartStream&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;'name'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'upload_file'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;'contents'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;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;'path/to/file'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'r'&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;// ... more fields&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$request&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;Request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;'POST'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
    &lt;span class=&quot;s1&quot;&gt;'https://xyz.acme.dev/api/upload'&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;$multipart&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$client&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If required, you can now pass around this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$request&lt;/code&gt; object as needed before actually sending it with the Guzzle client.&lt;/p&gt;
</description>
        <pubDate>Sun, 21 Feb 2016 00:00:00 +0000</pubDate>
        <link>http://blog.philipp-rieber.net/2016/02/21/creating-a-psr-7-guzzle-request-object-with-form-data/</link>
        <guid isPermaLink="true">http://blog.philipp-rieber.net/2016/02/21/creating-a-psr-7-guzzle-request-object-with-form-data/</guid>
        
        
      </item>
    
      <item>
        <title>Using Doctrine Naming Strategies in Symfony</title>
        <description>&lt;p&gt;Frequently, I’m stumbling upon very verbose Doctrine metadata definitions that translate each and every table and column definition from &lt;em&gt;camelCase&lt;/em&gt; names to names separated by underscores, e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;firstName&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;first_name&lt;/code&gt;. But did you know that can simply get rid of all this noise by implementing a Doctrine naming strategy?&lt;/p&gt;

&lt;p&gt;Let’s consider such a verbose sample entity definition for a person:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s&quot;&gt;Acme\MyService\Domain\Person&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;entity&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;table&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;person&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# ...&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;column&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;first_name&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;string&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;column&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;last_name&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;string&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;createdAt&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;column&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;created_at&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;datetime&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Or, using annotations:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&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;Doctrine\ORM\Mapping&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ORM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;cd&quot;&gt;/**
 * @ORM\Entity
 * @ORM\Table(name=&quot;person&quot;)
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Person&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
    
    &lt;span class=&quot;cd&quot;&gt;/**
     * @ORM\Column(name=&quot;first_name&quot;, type=&quot;string&quot;)
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$firstName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;cd&quot;&gt;/**
     * @ORM\Column(name=&quot;last_name&quot;, type=&quot;string&quot;)
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$lastName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;cd&quot;&gt;/**
     * @ORM\Column(name=&quot;created_at&quot;, type=&quot;datetime&quot;)
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$created_at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;    
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It seems quite verbose to translate the &lt;em&gt;camelCase&lt;/em&gt; entity table name and properties names to &lt;em&gt;under_score&lt;/em&gt; table and column names, e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Person&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;person&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;firstName&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;first_name&lt;/code&gt; etc. Furthermore, it is quite prone to become inconsistent if someone forgets it for a column that’s added later. So why not automate the translation?&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/reference/namingstrategy.html&quot;&gt;Doctrine Naming Strategies&lt;/a&gt; to the rescue! Doctrine naming strategies allow to define how entity class names and properties are translated to table and column names if they are not provided by the metadata. By default, Doctrine does not change anything and in the example above you’d end up with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Person&lt;/code&gt; table and the column names &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;firstName&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lastName&lt;/code&gt; etc. But by configuring the &lt;em&gt;Underscore Naming Strategy&lt;/em&gt; you’ll get exactly what you want – without all the table and column config noise in your metadata:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s&quot;&gt;Acme\MyService\Domain\Person&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;entity&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# ...&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;string&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;string&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;createdAt&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;datetime&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Or, using annotations:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&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;Doctrine\ORM\Mapping&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ORM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;cd&quot;&gt;/**
 * @ORM\Entity
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Person&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
    
    &lt;span class=&quot;cd&quot;&gt;/**
     * @ORM\Column(type=&quot;string&quot;)
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$firstName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;cd&quot;&gt;/**
     * @ORM\Column(type=&quot;string&quot;)
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$lastName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;cd&quot;&gt;/**
     * @ORM\Column(type=&quot;datetime&quot;)
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$created_at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;    
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;How to set this up? If using Symfony, it’s as simple as adding a configuration parameter &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;doctrine.orm.entity_managers.default.naming_strategy&lt;/code&gt; to your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.yml&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;doctrine&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;dbal&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# ...&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;orm&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# ...&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;entity_managers&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;na&quot;&gt;naming_strategy&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;doctrine.orm.naming_strategy.underscore&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If using plain PHP, you can check the &lt;a href=&quot;http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/reference/namingstrategy.html&quot;&gt;Doctrine docs&lt;/a&gt; for the few lines you need to add.&lt;/p&gt;

&lt;p&gt;By providing a custom implementation of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Doctrine\ORM\Mapping\NamingStrategy&lt;/code&gt;, you can also easily define your own naming strategy. This comes in handy if for example you need to follow naming guidelines like prefixing every table name, e.g. by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tbl_&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;By the way, as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;string&lt;/code&gt; is always the default data type, so you can even skip this config for simple columns by only putting a tilde &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~&lt;/code&gt; character:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s&quot;&gt;Acme\MyService\Domain\Person&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;entity&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# ...&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;firstName&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;lastName&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;createdAt&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;datetime&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When using annotations, just leave out the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;type&lt;/code&gt; definition:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&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;Doctrine\ORM\Mapping&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ORM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;cd&quot;&gt;/**
 * @ORM\Entity
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Person&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
    
    &lt;span class=&quot;cd&quot;&gt;/**
     * @ORM\Column(type=&quot;string&quot;)
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$firstName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;cd&quot;&gt;/**
     * @ORM\Column(type=&quot;string&quot;)
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$lastName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;cd&quot;&gt;/**
     * @ORM\Column(type=&quot;datetime&quot;)
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$created_at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will finally result in the following SQL definition, which is the same as for the verbose metadata definition from the beginning:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TABLE&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`person`&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* ... */&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;`first_name`&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;varchar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLLATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8_unicode_ci&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;`last_name`&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;varchar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLLATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8_unicode_ci&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;`created_at`&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;datetime&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;`person_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;n&quot;&gt;ENGINE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InnoDB&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CHARSET&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;utf8&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLLATE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;utf8_unicode_ci&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Sat, 20 Feb 2016 00:00:00 +0000</pubDate>
        <link>http://blog.philipp-rieber.net/2016/02/20/using-doctrine-naming-strategies-in-symfony/</link>
        <guid isPermaLink="true">http://blog.philipp-rieber.net/2016/02/20/using-doctrine-naming-strategies-in-symfony/</guid>
        
        
      </item>
    
      <item>
        <title>Integrating PHP Coding Standards Fixer with PhpStorm</title>
        <description>&lt;p&gt;Fixing coding standard issue individually is very tedious, e.g after running a static code analysis tool or after being declined by a code sniffer pre-commit hook. To ease these kind of tasks you may consider using SensioLabs’s awesome little CLI tool called &lt;a href=&quot;http://cs.sensiolabs.org/&quot;&gt;PHP Coding Standards Fixer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can simply run the &lt;em&gt;PHP Coding Standards Fixer&lt;/em&gt; recursively on a directory or on a single file and it’ll make your PHP files mostly compliant with &lt;a href=&quot;http://www.php-fig.org/psr/psr-1/&quot;&gt;PSR-1&lt;/a&gt;/&lt;a href=&quot;http://www.php-fig.org/psr/psr-2/&quot;&gt;PSR-2&lt;/a&gt; or Symfony coding standards, respectively. This vastly unburdens you from doing mindless and repetitive tasks. In addition, your coding style then relies on accepted standards, so there’s no pointless dispute about details.&lt;/p&gt;

&lt;p&gt;Using &lt;a href=&quot;http://brew.sh/&quot;&gt;Homebrew&lt;/a&gt;, installing the &lt;em&gt;PHP CS Fixer&lt;/em&gt; is as simple as:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;brew &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;homebrew/php/php-cs-fixer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For other platforms and installation options check out the &lt;a href=&quot;http://cs.sensiolabs.org/&quot;&gt;project page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To fix code styles recursively in all PHP files of a directory:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;php-cs-fixer fix /path/to/dir
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To fix code styles in a single PHP file:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;php-cs-fixer fix /path/to/file
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There are very fine-grained options to define the fixes to apply, but using the default &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;symfony&lt;/code&gt; level should usually be a good choice to be as close as possible to the Symfony defaults. This already saves much time when applied from time to time or before a new commit to your VCS. Of course, you can also do a dry run first and display a diff of all the changes to be made. Check out &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;php-cs-fixer help fix&lt;/code&gt; for all the details.&lt;/p&gt;

&lt;p&gt;You can also integrate the tool into PhpStorm so that you can apply style fixes by executing a custom shortcut. This is possible by setting up an &lt;em&gt;External Tool&lt;/em&gt; definition in PhpStorm: Got to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Preferences &amp;gt; Tools &amp;gt; External Tools &amp;gt; + (Create Tool)&lt;/code&gt; and fill in the details about how to execute the &lt;em&gt;PHP CS Fixer&lt;/em&gt; (for convenience, you can simply copy&amp;amp;paste the field values given below the screenshot):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/php-cs-fixer-in-phpstorm-external-tools.png&quot; alt=&quot;Setting up PHP CS Fixer as an external tool in PhpStorm&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;Name:&lt;/em&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;php-cs-fixer&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Program:&lt;/em&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/local/bin/php-cs-fixer&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Parameters:&lt;/em&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--level=symfony --verbose --config=sf23 fix &quot;$FileDir$/$FileName$&quot;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Working directory:&lt;/em&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$ProjectFileDir$&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then navigate to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Preferences &amp;gt; Keymap&lt;/code&gt;, search for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;php-cs-fixer&lt;/code&gt; and assign a custom shortcut, e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ctrl+Alt+P&lt;/code&gt;. Now, when you open up a PHP file in your editor and hit your assigned shortcut, the code gets formatted according to your external tool definition of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;php-cs-fixer&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Another nice feature of the &lt;em&gt;PHP CS Fixer&lt;/em&gt; is to add a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.php_cs&lt;/code&gt; file at the project’s root to improve the tool’s integration by giving sensible default options. This way it’ll be quite easy for example to additionally enforce PHP’s short array syntax or to give a default list of directories to be analysed.&lt;/p&gt;

&lt;p&gt;Of course, it’s should also possible to integrate the &lt;em&gt;PHP CS Fixer&lt;/em&gt; into an automated process.&lt;/p&gt;

&lt;p&gt;Fixing code styles might also be possible by using PhpStorm’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Reformat Code&lt;/code&gt; action, and I also use it from time to time to clean things up a bit, but from my experience this tool is a bit greedy and tries to fix things you may not want to be fixed, like chained calls of a fluent interface. Moreover, sharing code style definitions across teams becomes much easier when they are not tied to an IDE and can even be stored within the code repository (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.php_cs&lt;/code&gt; file). On the contrary what’s quite useful I think is PhpStorm’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Optimize imports&lt;/code&gt; action which cleans up and orders all the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;use&lt;/code&gt; statements – at least since PhpStorm is smart enough to not remove imports that are only used within annotations :-)&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;Project website:&lt;/em&gt; &lt;a href=&quot;http://cs.sensiolabs.org/&quot;&gt;http://cs.sensiolabs.org/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;GitHub repository:&lt;/em&gt; &lt;a href=&quot;https://github.com/FriendsOfPHP/PHP-CS-Fixer&quot;&gt;https://github.com/FriendsOfPHP/PHP-CS-Fixer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Fri, 19 Feb 2016 00:00:00 +0000</pubDate>
        <link>http://blog.philipp-rieber.net/2016/02/19/integrating-php-coding-standards-fixer-with-phpstorm/</link>
        <guid isPermaLink="true">http://blog.philipp-rieber.net/2016/02/19/integrating-php-coding-standards-fixer-with-phpstorm/</guid>
        
        
      </item>
    
      <item>
        <title>Optimize Debugging in a Symfony application</title>
        <description>&lt;p&gt;When debugging a Symfony application with Xdebug you might not only want to step through your own custom code, but also through the Symfony code itself. As a lot of Symfony’s core code is aggregated and optimized into a single file at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app/bootstrap.php.cache&lt;/code&gt; for performance reasons, you will not feel very comfortable reading non-highlighted, non-indented code of classes from multiple namespaces all assembled in the same file. And this is even true for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dev&lt;/code&gt; environment, where debugging usually happens. But some simple tweaks in the front controller will allow you to step through the original Symfony code if and only if a debug session was initialized.&lt;/p&gt;

&lt;p&gt;For this article we’ll use Symfony’s development front controller located at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;web/app_dev.php&lt;/code&gt;. Usually it looks like this:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$loader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;require_once&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;'/../app/bootstrap.php.cache'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;Debug&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;enable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;require_once&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;'/../app/AppKernel.php'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$kernel&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;AppKernel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'dev'&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;nv&quot;&gt;$kernel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;loadClassCache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$request&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;createFromGlobals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$kernel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;handle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$kernel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;terminate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The result in a debugging session is similar to the following screenshot when it comes to Symfony code:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/phpstorm-symfony-debugging-with-bootstrap-cache.png&quot; alt=&quot;PhpStorm Symfony Debugging with bootstrap.cache&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A dedicated &lt;a href=&quot;http://symfony.com/doc/current/cookbook/debugging.html&quot;&gt;cookbook in the Symfony documentation&lt;/a&gt; already describes how to disable the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bootstrap.php.cache&lt;/code&gt; file and the class cache:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// $loader = require_once __DIR__.'/../app/bootstrap.php.cache';&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$loader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;require_once&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;'/../app/autoload.php'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;Debug&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;enable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;require_once&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;'/../app/AppKernel.php'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$kernel&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;AppKernel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'dev'&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;c1&quot;&gt;// $kernel-&amp;gt;loadClassCache();&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$request&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;createFromGlobals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$kernel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;handle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$kernel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;terminate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;But in the end it recommends to revert the code changes after each debugging session. In practice, this would mean to toggle the changes all the time. So why not change the code only once and figure out at runtime if the current request is a Xdebug debugging session? Let’s introduce a boolean flag called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$enableCaching&lt;/code&gt; to switch between enabled and disabled caches. The following code corresponds to the default:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$disableCaching&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;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$disableCaching&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;$loader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;require_once&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;'/../vendor/autoload.php'&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;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$loader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;require_once&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;'/../app/bootstrap.php.cache'&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;nc&quot;&gt;Debug&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;enable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;require_once&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;'/../app/AppKernel.php'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$kernel&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;AppKernel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'dev'&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;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;$disableCaching&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;$kernel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;loadClassCache&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;$request&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;createFromGlobals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$kernel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;handle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$kernel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;terminate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;An initialized Xdebug debugging session can be identified by checking for these things:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xdebug&lt;/code&gt; extension must be loaded &lt;strong&gt;AND&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;one of these must be true:
    &lt;ul&gt;
      &lt;li&gt;GET parameter &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;XDEBUG_SESSION_START&lt;/code&gt; is set &lt;strong&gt;OR&lt;/strong&gt;&lt;/li&gt;
      &lt;li&gt;Cookie &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;XDEBUG_SESSION&lt;/code&gt; is set &lt;strong&gt;OR&lt;/strong&gt;&lt;/li&gt;
      &lt;li&gt;php.ini setting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xdebug.remote_autostart&lt;/code&gt; is enabled&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This results in a slightly adapted development front controller:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$disableCaching&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;extension_loaded&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'xdebug'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;isset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$_REQUEST&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'XDEBUG_SESSION_START'&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;k&quot;&gt;isset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$_COOKIE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'XDEBUG_SESSION'&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;ini_get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'xdebug.remote_autostart'&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;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$disableCaching&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;$loader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;require_once&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;'/../vendor/autoload.php'&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;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$loader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;require_once&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;'/../app/bootstrap.php.cache'&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;nc&quot;&gt;Debug&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;enable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;require_once&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;'/../app/AppKernel.php'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$kernel&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;AppKernel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'dev'&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;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;$disableCaching&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;$kernel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;loadClassCache&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;$request&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;createFromGlobals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$kernel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;handle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$kernel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;terminate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Contrary to the previous screenshot you’ll now see a pretty useful result when it comes to Symfony code:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/phpstorm-symfony-debugging-without-bootstrap-cache.png&quot; alt=&quot;PhpStorm Symfony Debugging without bootstrap.cache&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Happy debugging!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you want learn more about initializing Xdebug debugging session, check out my blog post about &lt;a href=&quot;http://www.sessiondigital.de/blog/connecting-xdebug-to-phpstorm&quot;&gt;Connecting Xdebug to PhpStorm&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</description>
        <pubDate>Tue, 11 Aug 2015 00:00:00 +0000</pubDate>
        <link>http://blog.philipp-rieber.net/2015/08/11/optimize-debugging-in-a-symfony-application/</link>
        <guid isPermaLink="true">http://blog.philipp-rieber.net/2015/08/11/optimize-debugging-in-a-symfony-application/</guid>
        
        
      </item>
    
      <item>
        <title>Run phpspec when saving files with gulp and PhpStorm</title>
        <description>&lt;p&gt;In our weekly Code Kata at &lt;a href=&quot;http://www.sessiondigital.de/&quot;&gt;work&lt;/a&gt;, we’re exercising TDD using &lt;a href=&quot;http://phpspec.net/&quot;&gt;phpspec&lt;/a&gt;. TDD means switching between coding and running the tests all the time, may causing cramps by abuse of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Cmd+Tab&lt;/code&gt;. So why not automate the test runs whenever a source file changes and show a decent notification about success or failure?&lt;/p&gt;

&lt;p&gt;This article shows two different approaches to automatically run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phpspec&lt;/code&gt; whenever a source or spec file was changed in your codebase.&lt;/p&gt;

&lt;h1 id=&quot;gulp-file-watcher&quot;&gt;Gulp File Watcher&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;http://gulpjs.com/&quot;&gt;Gulp&lt;/a&gt; is a &lt;a href=&quot;https://nodejs.org/&quot;&gt;Node.js&lt;/a&gt; based task runner. It allows you to create and run lightweight customized tasks on the command line and provides tons of plugins, e.g. for desktop notifications or running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phpspec&lt;/code&gt; with specific options – exactly what we need for our purposes. After installing Node.js, gulp first needs to be installed globally by using the Node Package Manager &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm&lt;/code&gt;:&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;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; gulp&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Gulp also needs to be installed locally for each project that makes use of it – just as well as the desired gulp plugins. To install local Node packages, just type a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node install&lt;/code&gt; command right in the project’s root directory:&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;nv&quot;&gt;$ &lt;/span&gt;npm &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;gulp gulp-notify gulp-phpspec &lt;span class=&quot;nt&quot;&gt;--save-dev&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Packages and their dependencies are installed into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node_modules/&lt;/code&gt; directory by default, which should be ignored by your version control system. If you have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt; file in place (which in contrast should be under version control) to describe your Node dependencies, the  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--save-dev&lt;/code&gt; option appends the installed packages and their respective versions to the development dependencies section:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&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;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;gulp&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;^3.8.7&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;gulp-notify&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;^1.5.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;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;gulp-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;^0.2.5&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;p&gt;With &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt;, you or your fellow teammates just need to run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm install&lt;/code&gt; without any argument to get the exact same setup of Node module on their machine. Think of it as &lt;a href=&quot;https://getcomposer.org/&quot;&gt;Composer&lt;/a&gt; for Node.&lt;/p&gt;

&lt;p&gt;Gulp tasks are defined in a file called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gulpfile.js&lt;/code&gt; in the project’s root directory. First, we import the plugins and assign them to variables:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;gulp&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;gulp&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;c1&quot;&gt;// gulp task runner&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;phpspec&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;gulp-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;span class=&quot;c1&quot;&gt;// for running phpspec&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;notify&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;gulp-notify&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;c1&quot;&gt;// for desktop notifications&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Then, we create a stub task that will run the phpspec tests later:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;task&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;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;console&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;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Run 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;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You can already try this task on the command line, providing the task name &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test&lt;/code&gt; to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gulp&lt;/code&gt; 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;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;gulp &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;12:16:25] Using gulpfile ~/test/gulpfile.js
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;12:16:25] Starting &lt;span class=&quot;s1&quot;&gt;'test'&lt;/span&gt;...
Run phpspec ...
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;12:16:25] Finished &lt;span class=&quot;s1&quot;&gt;'test'&lt;/span&gt; after 67 μs&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now it’s time to fill the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test&lt;/code&gt; task with real code:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;task&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;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;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;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;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;v&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;notify&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;clear&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;formatter&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;pretty&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;gulp&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;spec/**/*.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;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&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;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./bin/phpspec run&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;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;nx&quot;&gt;on&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;error&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;notify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;onError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;title&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;Crap&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;Your tests failed!&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;icon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;__dirname&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;/node_modules/gulp-phpspec/assets/file-watcher/test-fail.jpeg&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;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;notify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;title&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;Success&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;All tests have returned green!&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;icon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;__dirname&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;/node_modules/gulp-phpspec/assets/file-watcher/test-pass.jpeg&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;In &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;options&lt;/code&gt;, you can specify whatever command line options you want to run phpspec with, e.g. for pretty or verbose output or if you wish to clear the console after every test run. With &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gulp.src('spec/**/*.php')&lt;/code&gt;, gulp finds all the PHP files in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spec/&lt;/code&gt; directory recursively (using a &lt;em&gt;glob&lt;/em&gt; pattern) and then pipes them into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phpspec&lt;/code&gt; command with the options from above using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pipe(phpspec('./bin/phpspec run', options))&lt;/code&gt;. You may need to adjust the path to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phpspec&lt;/code&gt; executable. Now, when running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gulp test&lt;/code&gt; in your project’s root folder, every phpspec test gets executed. Depending on test success or failure, the appropriate method from the &lt;a href=&quot;https://www.npmjs.com/package/gulp-notify&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gulp-notify&lt;/code&gt;&lt;/a&gt; plugin gets called and shows a nice desktop notification – depending on your operating system.&lt;/p&gt;

&lt;p&gt;To implement a &lt;em&gt;watch&lt;/em&gt; functionality that is monitoring files for changes and then automatically runs the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test&lt;/code&gt; task, we implement another task called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;watch&lt;/code&gt;, which makes use of a native gulp feature to watch for file changes:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;task&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;watch&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;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&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;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;spec/**/*.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;src/**/*.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;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;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The first parameter of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gulp.watch()&lt;/code&gt; indicates the files we wish to watch for changes, i.e. in our case all the PHP source and spec files. The second parameter specifies the task(s) to run when a file change is detected, i.e. in our case only the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test&lt;/code&gt; task. Now you may start the file watcher with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gulp watch&lt;/code&gt;. But gulp also allows you to specify a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;default&lt;/code&gt; task that gets executed whenever you do not provide a task name to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gulp&lt;/code&gt; command:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;task&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;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;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;watch&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;In the second parameter, instead of a callback method, we can also provide an array of existing task names that we wish to run. To run the tests once and then start the file watcher, there’s now nothing more to it than just running:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If we put everything together, we end up with a quite straightforward &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gulpfile.js&lt;/code&gt; solution, allowing us to watch for file changes and execute the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phpspec&lt;/code&gt; tests:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// gulpfile.js&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;gulp&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;gulp&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;phpspec&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;gulp-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;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;notify&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;gulp-notify&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;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;task&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;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;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;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;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;v&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;notify&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;clear&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;formatter&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;pretty&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;gulp&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;spec/**/*.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;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&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;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./bin/phpspec run&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;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;nx&quot;&gt;on&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;error&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;notify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;onError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;title&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;Crap&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;Your tests failed!&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;icon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;__dirname&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;/node_modules/gulp-phpspec/assets/file-watcher/test-fail.jpeg&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;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;notify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;title&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;Success&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;All tests have returned green!&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;icon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;__dirname&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;/node_modules/gulp-phpspec/assets/file-watcher/test-pass.jpeg&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;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;task&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;watch&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;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&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;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;spec/**/*.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;src/**/*.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;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;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;task&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;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;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;watch&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 just open a console window (e.g. integrated in PhpStorm: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Alt+F12&lt;/code&gt;), work on your code and watch the test runs every time you save a file (e.g. in PhpStorm: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Cmd+S&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;A successful test run in PhpStorm looks like thi:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/file-watcher/gulp-success.jpg&quot; alt=&quot;Gulp File Watcher for phpspec&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A failed test run in PhpStorm looks like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/file-watcher/gulp-failure.jpg&quot; alt=&quot;Gulp File Watcher for phpspec&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;phpstorm-file-watcher&quot;&gt;PhpStorm file watcher&lt;/h1&gt;

&lt;p&gt;Modern IDEs also provide solutions to create file watchers.&lt;/p&gt;

&lt;p&gt;In my IDE of choice – PhpStorm – this feature is simply called &lt;em&gt;File Watchers&lt;/em&gt;. There’s even built-in support for popular transcompilers like Sass or CoffeeScript that compile to their CSS or JavaScript counterpart on file save, respectively. For our purposes we can easily add a custom file watcher by importing a ready made solution from &lt;a href=&quot;https://github.com/vivait/phpspec-PhpStorm-file-watcher&quot;&gt;Github&lt;/a&gt;. Save the &lt;a href=&quot;https://raw.githubusercontent.com/vivait/phpspec-PhpStorm-file-watcher/master/phpspec-2-watcher.xml&quot;&gt;raw XML file&lt;/a&gt; somewhere and import it from  &lt;strong&gt;Preferences &amp;gt; File Watcher&lt;/strong&gt; using the &lt;strong&gt;Import&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/file-watcher/phpstorm-config.jpg&quot; alt=&quot;PhpStorm File Watcher for phpspec&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;All the options are quite self-explanatory, but you may adopt some little things like always showing the console, whether it is an erroneous or a successful test run. That way, you may be more confident that the tests ran smoothly.&lt;/p&gt;

&lt;p&gt;A successful test run in PhpStorm looks like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/file-watcher/phpstorm-success.jpg&quot; alt=&quot;PhpStorm File Watcher for phpspec&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A failed test run in PhpStorm looks like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/file-watcher/phpstorm-failure.jpg&quot; alt=&quot;PhpStorm File Watcher for phpspec&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As you may have have noticed, there is no desktop notifications. Implementing desktop notifications is possible, but requires additional work that I’ll leave as an exercise to the interested reader.&lt;/p&gt;

&lt;h1 id=&quot;gulp-file-watcher-vs-phpstorm-file-watcher&quot;&gt;Gulp file watcher vs. PhpStorm file watcher&lt;/h1&gt;

&lt;p&gt;Although gulp requires Node.js, I prefer the gulp solution to the IDE File Watcher because:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;it works in every IDE or even without&lt;/li&gt;
  &lt;li&gt;the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gulpfile.js&lt;/code&gt; can be under version control and easily distributed with a project&lt;/li&gt;
  &lt;li&gt;it provides desktop notifications out-of-the-box&lt;/li&gt;
&lt;/ul&gt;

</description>
        <pubDate>Sat, 01 Aug 2015 00:00:00 +0000</pubDate>
        <link>http://blog.philipp-rieber.net/2015/08/01/run-phpspec-when-saving-files-with-gulp-and-phpstorm/</link>
        <guid isPermaLink="true">http://blog.philipp-rieber.net/2015/08/01/run-phpspec-when-saving-files-with-gulp-and-phpstorm/</guid>
        
        
      </item>
    
      <item>
        <title>Moving to the cloud part 7: Enabling Elastic Beanstalk</title>
        <description>&lt;p&gt;Finally, after preparing our application during the &lt;a href=&quot;/2013/03/09/moving-to-the-cloud-part-1-intentions/&quot;&gt;last few months bit by bit&lt;/a&gt;, it was time for the last and most important step: move the application code to an auto-scaling multi-server environment in the cloud and do a smooth DNS switch for the productive application. First we thought doing this with EC2 directly, but after some investigations we found solutions like Scalr, OpsWorks (the former Scalarium) or Elastic Beanstalk doing the heavy work for us. We decided in favor for &lt;strong&gt;Elastic Beanstalk&lt;/strong&gt; - let’s see why and how.&lt;/p&gt;

&lt;p&gt;The first time I played around with &lt;a href=&quot;http://aws.amazon.com/ec2/&quot;&gt;Amazon’s EC2&lt;/a&gt; service some years ago I was completely excited about all the possibilities: Setting up server instances on demand by simple mouse clicks, choosing between different instance types regarding CPU and RAM size for the specific needs of an application, wiring several instances together with a load balancer in front - and only paying for what’s currently in use. Suddenly, even small companies became able to provide highly scalable multi-server environments without buying resources in advance. No financial risk if the application fails. No sysadmin that needs hours or days to configure fresh root servers. Easily extendable setup. No long running contracts. No setup fees.&lt;/p&gt;

&lt;p&gt;Mostly, if you find a solution for an issue, you’ll get new issues when implementing this solution. Ok, with EC2 you can start whatever server instance type you need at any time. You can do this by a mouse click in the Amazon console or by programmatically using the API. You can create a load balancer and add instances to it. You can add more instances if the load grows, you can terminate instances as soon as you no longer need them. You can SSH onto any instance of your cluster and install packages, application code or cronjobs. This is really great - but you’ll want more for a productive application. You’ll want the scaling to be triggered automatically by the current load. You’ll want all instances to be configured the same. You’ll want to roll out new code to all instances in one go. You’ll want some cronjobs to be running only on one instance of the cluster that never gets terminated by autoscaling. You’ll want to have health checks and monitoring.&lt;/p&gt;

&lt;p&gt;There are some services on the internet that help you with exactly this kind of issues. In other words, they help you manage your Amazon resources with an abstraction layer on top of the raw Amazon webservices. Those kind of abstraction layers are called &lt;strong&gt;Platform-as-a-Service (PaaS)&lt;/strong&gt; - you get all the single services combined to the whole application platform. For instance, you can create named server farms in a nice browser GUI, configure the autoscaling triggers, deploy application code to all instances at once with no downtime etc. Some of them are third party services like &lt;a href=&quot;http://www.rightscale.com/&quot;&gt;Rightscale&lt;/a&gt; or &lt;a href=&quot;http://www.scalr.com/&quot;&gt;Scalr&lt;/a&gt;. You’ll need to pay a service fee on top of the Amazon resources you’re managing with the service. But Amazon itself also provides two free services fo this purpose in the AWS console: &lt;a href=&quot;http://aws.amazon.com/opsworks/&quot;&gt;OpsWork&lt;/a&gt; (formerly &lt;a href=&quot;http://scalarium.com&quot;&gt;Scalarium&lt;/a&gt;) and &lt;a href=&quot;http://aws.amazon.com/elasticbeanstalk/&quot;&gt;Elastic Beanstalk&lt;/a&gt;. Scalarium was acquired by Amazon in the beginning of 2013 and is the foundation of OpsWorks. It makes heavy use of the configuration management software &lt;a href=&quot;http://www.opscode.com/chef/&quot;&gt;Chef&lt;/a&gt; and can therefore be highly customized.  Elastic Beanstalk was the first Amazon PaaS and is less complex. It is using several Amazon webservices like EC2, Elastic Load Balancer (ELB), S3 and ties them together with a configuration made by the user.&lt;/p&gt;

&lt;p&gt;OpsWorks will probably be the tool of choice for our next cloud migration. But when we started our migration it was freshly released and at first glance Chef cookbooks are not your best friends. So for this time, we put our trust in the fully established and well documented Elastic Beanstalk service which is free of charge.&lt;/p&gt;

&lt;p&gt;In Elastic Beanstalk, you can host multiple applications. Each application allows you to have multiple environments, so you can for instance setup a &lt;em&gt;Staging&lt;/em&gt; environment with only a single and cheap EC2 instance and an autoscaling &lt;em&gt;Production&lt;/em&gt; environment using a powerful but expensive EC2 instance type.&lt;/p&gt;

&lt;h2 id=&quot;setup-an-elastic-beanstalk-application&quot;&gt;Setup an Elastic Beanstalk application&lt;/h2&gt;

&lt;p&gt;To create your first PaaS application, login to the &lt;a href=&quot;https://console.aws.amazon.com/elasticbeanstalk&quot;&gt;Elastic Beanstalk console&lt;/a&gt;. At first, adjust the appropriate region for your needs, then click on &lt;em&gt;Create New Application&lt;/em&gt;. Enter a name and description for your application:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/aws/eb-1.jpg&quot; alt=&quot;EB-1&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Then, step-by-step, you will be guided through the process to setup your first environment within your application. First, select your solution stack and if you wish an autoscaling environment. Actual triggers for autoscaling – like CPU or RAM usage – will be setup later.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/aws/eb-2.jpg&quot; alt=&quot;EB-2&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In the third step, you can upload your application code as a ZIP package or, in the first instance, opt for a sample application. We’ll go with the sample application and install a custom application later on:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/aws/eb-3.jpg&quot; alt=&quot;EB-3&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Provide some info for your environment name, an unique &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;elasticbeanstalk.com&lt;/code&gt; sub domain, e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foobar.elasticbeanstalk.com&lt;/code&gt;, and a description. Please note that your real application URL is fully customizable using &lt;a href=&quot;/2013/03/18/moving-to-the-cloud-part-3-enabling-route-53/&quot;&gt;Amazon Route53&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/aws/eb-4.jpg&quot; alt=&quot;EB-4&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We don’t need any additional resources at this point, so let’s just skip the next step. Regarding the RDS instance, it’s even more convenient to do the setup &lt;a href=&quot;/2013/05/19/moving-to-the-cloud-part-6-enabling-rds/&quot;&gt;manually&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/aws/eb-5.jpg&quot; alt=&quot;EB-5&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In the configuration details, you can specify the EC2 instance type for your environment. Please note: check out the &lt;a href=&quot;http://aws.amazon.com/ec2/pricing/&quot;&gt;pricing&lt;/a&gt; before selecting an instance type. Powerful instance types can get &lt;em&gt;real&lt;/em&gt; expensive, so you should go with a &lt;strong&gt;micro&lt;/strong&gt; instance first. Besides, give an EC2 keypair so you can SSH into the managed EC2 machines and an email address for status notifications. You can also specify a health check URL within your application which will is pinged every few minutes to check if your application is still alive.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/aws/eb-6.jpg&quot; alt=&quot;EB-6&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Review all information and finally &lt;em&gt;Create&lt;/em&gt; your platform:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/aws/eb-7.jpg&quot; alt=&quot;EB-7&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You can follow the launch process of your first application environment by looking at the events log. This may take some time to complete.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/aws/eb-8.jpg&quot; alt=&quot;EB-8&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;After the creation process has completed you’ll see a green checkmark for the health status …&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/aws/eb-10.jpg&quot; alt=&quot;EB-10&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;… and you’re able to access the sample application by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;elasticbeanstalk.com&lt;/code&gt; sub domain you specified before, e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://foobar.elasticbeanstalk.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/aws/eb-12.jpg&quot; alt=&quot;EB-12&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The EC2 console now contains EC2 instances for your new Elastic Beanstalk environment:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/aws/eb-13.jpg&quot; alt=&quot;EB-13&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A load balancer has been set up automatically in front of your EC2 instance(s):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/aws/eb-14.jpg&quot; alt=&quot;EB-14&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;And there’s also a new security group for your new environment, allowing access to the web server on port 80 and via SSH on port 22:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/aws/eb-15.jpg&quot; alt=&quot;EB-15&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Looking at your S3 console, you’ll notice a fresh S3 bucket related to your Elastic Beanstalk environment. This is were new release versions of your application code get stored, so they can be deployed and also be roll-backed easily.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/aws/eb-16.jpg&quot; alt=&quot;EB-16&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;To deploy a custom application, go back to the dashboard of your Elastic Beanstalk environment and upload a ZIP package of your application code by clicking on &lt;em&gt;Upload and Deploy&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/aws/eb-17.jpg&quot; alt=&quot;EB-17&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Again, you can follow the environment update by looking at the &lt;em&gt;Recent Events&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/aws/eb-18.jpg&quot; alt=&quot;EB-18&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As soon as the deployment is complete you should be able to access your application by entering the chosen sub domain in your browser, e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://foobar.elasticbeanstalk.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What actually happens during deployment is that a ZIP archive of your whole application is uploaded to a dedicated S3 bucket first. Then a so-called &lt;em&gt;Application Version&lt;/em&gt; is created from your upload and a deployment to the Elastic Beanstalk gets triggered. No matter how many servers are currently running behind the load balancer in your environment, Elastic Beanstalk takes care of the roll-out to all of them and switching everything live in the end.&lt;/p&gt;

&lt;h2 id=&quot;customizing&quot;&gt;Customizing&lt;/h2&gt;

&lt;p&gt;If your application has specific server requirements like additional software packages, a different document root, specific PHP settings or if you want to add custom files (e.g. containing specific parameters for your database connection), it is possible to include an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/.ebextensions&lt;/code&gt; directory in your zipped application code. All files using the extension &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*.config&lt;/code&gt; in this directory can be used to specify custom configuration. For instance, if you need the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lynx&lt;/code&gt; package installed, an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.htaccess&lt;/code&gt; secured area, a custom &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parameters.yml&lt;/code&gt; in a Symfony project, some custom &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;php.ini&lt;/code&gt; settings, a cron job to send out what’s in the Swiftmailer file spool and set an appropriate timezone for the EC2 instances, you may use a configuration file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/.ebextensions/app.config&lt;/code&gt; containing 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;packages:
  yum:
    lynx: &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;

files:
  &lt;span class=&quot;s2&quot;&gt;&quot;/tmp/htaccess&quot;&lt;/span&gt;:
    mode: &lt;span class=&quot;s2&quot;&gt;&quot;644&quot;&lt;/span&gt;
    owner: webapp
    group: webapp
    content: |
      AuthName &lt;span class=&quot;s2&quot;&gt;&quot;My secured area&quot;&lt;/span&gt;
      AuthType Basic
      AuthUserFile /var/app/current/.htpasswd
      require user admin
  &lt;span class=&quot;s2&quot;&gt;&quot;/tmp/parameters.yml&quot;&lt;/span&gt;:
    mode: &lt;span class=&quot;s2&quot;&gt;&quot;644&quot;&lt;/span&gt;
    owner: webapp
    group: webapp
    content: |
      parameters:
        database_driver: pdo_mysql
        database_host: omdb.vnbnlwvfvi3zc.eu-west-1.rds.amazonaws.com
        database_port: ~
        database_name: app
        database_user: app
        database_password: JKIAJ97WSC3L9GFZS7P2
  &lt;span class=&quot;s2&quot;&gt;&quot;/etc/php.d/app.ini&quot;&lt;/span&gt;:
    mode: &lt;span class=&quot;s2&quot;&gt;&quot;644&quot;&lt;/span&gt;
    content: |
      date.timezone &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; Europe/Berlin
  &lt;span class=&quot;s2&quot;&gt;&quot;/tmp/app-crons&quot;&lt;/span&gt;:
    mode: &lt;span class=&quot;s2&quot;&gt;&quot;644&quot;&lt;/span&gt;
    content: |
      &lt;span class=&quot;nv&quot;&gt;MAILTO&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;cron@app.com
      &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;k&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; webapp /var/app/current/app/console swiftmailer:spool:send &lt;span class=&quot;nt&quot;&gt;--env&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;stage &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; /dev/null 2&amp;gt;&amp;amp;1

commands:
  10_servertime:
    &lt;span class=&quot;nb&quot;&gt;command&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;cp&lt;/span&gt; /usr/share/zoneinfo/Europe/Berlin /etc/localtime &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'ZONE=&quot;Europe/Berlin&quot;'&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;tee&lt;/span&gt; /etc/sysconfig/clock

container_commands:
  10_parameters:
    &lt;span class=&quot;nb&quot;&gt;command&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;mv&lt;/span&gt; /tmp/parameters.yml app/config/
  20_protection:
    &lt;span class=&quot;nb&quot;&gt;command&lt;/span&gt;: &lt;span class=&quot;s1&quot;&gt;'mv /tmp/htaccess .htaccess &amp;amp;&amp;amp; htpasswd -cb .htpasswd admin &quot;B0DEK/TK2k_p0FgPxK1&quot; &amp;amp;&amp;amp; chmod 444 .htpasswd'&lt;/span&gt;
  30_crons:
    &lt;span class=&quot;nb&quot;&gt;command&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;mv&lt;/span&gt; /tmp/app-crons /etc/cron.d/&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;There’s lot of &lt;a href=&quot;http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/customize-containers.html&quot;&gt;documentation&lt;/a&gt; how you can customize to your specific needs and how to execute custom commands during the deployment process.&lt;/p&gt;

&lt;h2 id=&quot;setup-a-deployment-script&quot;&gt;Setup a deployment script&lt;/h2&gt;

&lt;p&gt;Since all Amazon web services can be managed by powerful APIs, you can also do a deployment by wiring together some CLI commands in a shell script and by using the &lt;a href=&quot;http://aws.amazon.com/cli&quot;&gt;AWS Command Line Tools&lt;/a&gt; (which give you the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aws&lt;/code&gt; 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;&lt;span class=&quot;c&quot;&gt;# Application name on Elastic Beanstalk&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;APP&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;foobar&quot;&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Environment name on Elastic Beanstalk&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;staging&quot;&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# S3 bucket name of Elastic Beanstalk application&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;BUCKET&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;elasticbeanstalk-eu-west-1-294798127440&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Create a unique version string for this release&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;VERSION&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$ENV&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;-v_&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;date&lt;/span&gt; +%Y-%m-%d_%H-%M-%S&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Zip the application&lt;/span&gt;
zip &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$VERSION&lt;/span&gt;.zip /path/to/your/application

&lt;span class=&quot;c&quot;&gt;# Push zipped application to S3 - this may take a while&lt;/span&gt;
aws &lt;span class=&quot;nt&quot;&gt;--profile&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$APP&lt;/span&gt; s3 &lt;span class=&quot;nb&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$VERSION&lt;/span&gt;.zip s3://&lt;span class=&quot;nv&quot;&gt;$BUCKET&lt;/span&gt;/&lt;span class=&quot;nv&quot;&gt;$VERSION&lt;/span&gt;.zip
&lt;span class=&quot;c&quot;&gt;# Create application version&lt;/span&gt;
aws &lt;span class=&quot;nt&quot;&gt;--profile&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$APP&lt;/span&gt; elasticbeanstalk create-application-version &lt;span class=&quot;nt&quot;&gt;--application-name&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$APP&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--version-label&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$VERSION&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--source-bundle&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;S3Bucket&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$BUCKET&lt;/span&gt;,S3Key&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$VERSION&lt;/span&gt;.zip
&lt;span class=&quot;c&quot;&gt;# Trigger environment update&lt;/span&gt;
aws &lt;span class=&quot;nt&quot;&gt;--profile&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$APP&lt;/span&gt; elasticbeanstalk update-environment &lt;span class=&quot;nt&quot;&gt;--environment-name&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$ENV&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--version-label&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$VERSION&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The remaining question here is how to prepare the application code that gets zipped so that it can run properly and secure on the Elastic Beanstalk environment. You may need to setup a custom process here, e.g. to get rid of unnecessary files like development front controllers or uncompressed asset files. You can do this by by extending the shell script or by using build tools like &lt;a href=&quot;http://ant.apache.org/&quot;&gt;Ant&lt;/a&gt; or &lt;a href=&quot;https://www.phing.info/&quot;&gt;Phing&lt;/a&gt;. In the end, what you need to build, is a directory with your application code completely stripped down to the bare minimum of what’s really needed to run the application, maybe compressed assets and likely you need to include a configuration file appropriate for your target environment (database settings, API keys etc. for this specific environment). For the latter, you may also the custom configuration file feature shown above or environment variables. On Elastic Beanstalk, you can set environment variables easily in the environment configuration and they are available on every EC2 instance managed by your environment.&lt;/p&gt;

&lt;p&gt;One thing to note is that in a PHP application that uses Composer, you do not have to include your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/vendor&lt;/code&gt; directory. Elastic Beanstalk makes some assumption about your application, and if there’s a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;composer.json&lt;/code&gt; in your application root, it automatically does a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;composer install&lt;/code&gt; during deployment. This will save you a lot of time and bandwidth when transmitting your zipped application code.&lt;/p&gt;

&lt;h2 id=&quot;autoscaling&quot;&gt;Autoscaling&lt;/h2&gt;

&lt;p&gt;Finally, to enable autoscaling, go to the &lt;em&gt;Configuration&lt;/em&gt; page of your Elastic Beanstalk environment and enter a range of servers you’ll want your application to run on. For instance, you may want of minimum of 2 servers to be on the safe side, and a maximum of 4 to absorb peak loads. You can even setup a timetable for autoscaling – e.g. to prepare for your TV commercials – and also spread the EC2 instances across Availability Zones to be independent from regional outages etc.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/aws/eb-19.png&quot; alt=&quot;EB-19&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;more&quot;&gt;More&lt;/h2&gt;

&lt;p&gt;There are a way more features available on Elastic Beanstalk than be covered in this article. You can do for example far more customizations, there are special options for all the different platform stacks, zero-downtime deployments, SSL, usage of custom domains, integration of other AWS services etc. Just check out &lt;a href=&quot;http://docs.aws.amazon.com/elasticbeanstalk&quot;&gt;the extensive documentation&lt;/a&gt; for more information.&lt;/p&gt;
</description>
        <pubDate>Sat, 01 Jun 2013 00:00:00 +0000</pubDate>
        <link>http://blog.philipp-rieber.net/2013/06/01/moving-to-the-cloud-part-7-enabling-elastic-beanstalk/</link>
        <guid isPermaLink="true">http://blog.philipp-rieber.net/2013/06/01/moving-to-the-cloud-part-7-enabling-elastic-beanstalk/</guid>
        
        
      </item>
    
      <item>
        <title>Moving to the cloud part 6: Enabling RDS</title>
        <description>&lt;p&gt;In this part of my series we’ll get closer to the fundamentals of our application. In the &lt;a href=&quot;/2013/05/15/moving-to-the-cloud-part-5-enabling-ses/&quot;&gt;last article&lt;/a&gt; we’ve outsourced our mail server to the cloud. Now we want to do the same with our database server to get rid of all the tasks that come with hosting a database server like setup, configuration, maintenance, backups, security, replication or updates. Amazon provides a really straightforward solution: RDS&lt;/p&gt;

&lt;p&gt;Using &lt;a href=&quot;http://aws.amazon.com/rds&quot;&gt;Amazon RDS&lt;/a&gt; (Relational Database Service) is as simple as changing the database connection settings in our application’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parameters.yml&lt;/code&gt; to the ones provided in the &lt;a href=&quot;https://console.aws.amazon.com/rds&quot;&gt;AWS console&lt;/a&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;# parameters.yml&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# ...&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;database_host&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;vv6m55fk5jgz8tg.gh4ruwxi8vb4.eu-west-1.rds.amazonaws.com&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;database_port&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;database_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;database-name&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;database_user&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;database-user&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;database_password&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;VCXJAI9WEV9QZ2HL0BN9C&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;But how do we setup the database in RDS and how does Amazon handle all that stuff mentioned in the introduction?&lt;/p&gt;

&lt;p&gt;We just click on Launch a DB instance in the AWS console and choose our prefered database provider: MySQL&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/aws/RDS-1.png&quot; alt=&quot;RDS-1&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In the next dialog we choose from different options:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;MySQL version; in our example it’s the current GA release version 5.5&lt;/li&gt;
  &lt;li&gt;Instance Class, defining the size of our database engine; in our example it’s the smallest and cheapest: Micro&lt;/li&gt;
  &lt;li&gt;Multi-AZ Deployments would replicate our database instance in different availability zones providing enhanced availability in case of a failure. This is recommended for production environments&lt;/li&gt;
  &lt;li&gt;Allow automatic minor version updates, e.g. from 5.5.27 to 5.5.28&lt;/li&gt;
  &lt;li&gt;Choose identifier and credentials&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/aws/RDS-2.png&quot; alt=&quot;RDS-2&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This frees us from setting up the database server itself, from dealing with replication and from applying patch level updates every few weeks.&lt;/p&gt;

&lt;p&gt;In the next step we can enter a database name and select a security group. Security groups are a fundamental concept in AWS and they let us create some kind of different firewalls by specifying what services are available under which ports and for which IP addresses or subnets. For instance, we can restrict RDS instance access to a specific EC2 instance or our company’s static IP address. Security groups have to be setup separately in the RDS console as shown on the second screenshot.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/aws/RDS-3.png&quot; alt=&quot;RDS-3&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/aws/RDS-3a.png&quot; alt=&quot;RDS-3a&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This frees us from digging to deep into security concerns.&lt;/p&gt;

&lt;p&gt;In the next step we can define the backup retention period up to 35 days. RDS allows to restore the database to any second during the backup retention period (up to the last five minutes).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/aws/RDS-4.png&quot; alt=&quot;RDS-4&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This frees us completely from setting up, maintaining and monitoring database backups.&lt;/p&gt;

&lt;p&gt;In the last step we can verify all settings and then finally launch the database instance.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/aws/RDS-5.png&quot; alt=&quot;RDS-5&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The new database instance will be available a few minutes later.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/aws/RDS-6.png&quot; alt=&quot;RDS-6&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We then just need to copy the endpoint URL and the credentials chosen during the setup process to our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parameters.yml&lt;/code&gt; and the application is ready to establish a connection to RDS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance&lt;/strong&gt;
It is possible to use an RDS instance from outside the AWS ecosystem, for instance from your existing non-AWS server. This is very useful for testing or development purposes but you don’t want to do that in production. Connecting a database over the internet is just too slow. But as soon as our production move to EC2 or Elastic Beanstalk is complete we’ll also switch the database to RDS.&lt;/p&gt;
</description>
        <pubDate>Sun, 19 May 2013 00:00:00 +0000</pubDate>
        <link>http://blog.philipp-rieber.net/2013/05/19/moving-to-the-cloud-part-6-enabling-rds/</link>
        <guid isPermaLink="true">http://blog.philipp-rieber.net/2013/05/19/moving-to-the-cloud-part-6-enabling-rds/</guid>
        
        
      </item>
    
      <item>
        <title>Moving to the cloud part 5: Enabling SES</title>
        <description>&lt;p&gt;Sending emails from a Symfony2 application is no challenging task. Just configure the Swiftmailer library with a handful of simple parameters, create a message object, trigger the sending process and you are done. Things change slightly if you are responsible of the mail server at the same time. Setting up and maintaining mail server software may become a challenging task, especially if there are complaints about missing emails, security holes or spam issues. Moreover, sending from a cloud server is not very reliable because of its doubtful IP reputation. Amazon’s SES service provides relief.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://aws.amazon.com/ses&quot;&gt;Amazon’s SES&lt;/a&gt; (Simple Email Service) service frees us from setting up and maintaining a mail server by providing an email service with a single SMTP endpoint.&lt;/p&gt;

&lt;p&gt;Switching to SES is as simple as updating your Swiftmailer configuration. It should look similar to the following:&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;s&quot;&gt;// app/config/config.yml&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# ...&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;swiftmailer&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;transport&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;%mailer_transport%&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;%mailer_host%&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;%mailer_port%&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;encryption&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;%mailer_encryption%&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;%mailer_user%&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;%mailer_password%&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;It should be noted that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;encryption&lt;/code&gt; parameter is not part of the default configuration and no encryption is used by default. Since SES requires TLS encryption we need to add this setting.&lt;/p&gt;

&lt;p&gt;If you’ve signed up for AWS you can find your personal SMTP settings in the [SES Management Console] (https://console.aws.amazon.com/ses) and you can complete your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parameters.yml&lt;/code&gt; with it:&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;parameters&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# ...&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;mailer_transport&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;smtp&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;mailer_host&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;email-smtp.us-east-1.amazonaws.com&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# to be found in the SES console&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;mailer_user&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;SES-User&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# to be found in the SES console&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;mailer_password&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;SES-Password&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# to be found in the SES console&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;mailer_encryption&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;tls&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# TLS encryption required&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;mailer_port&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;25&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# 25, 465 or 587&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;That’s all – all your email will be sent through SES now and you can start thinking about shutting down your mail server.&lt;/p&gt;

&lt;p&gt;Remember that Amazon insists on high quality emails to prevent abuse. Otherwise your account may be disabled.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sandbox mode&lt;/strong&gt;
A fresh SES account runs in a sandbox mode. In the sandbox mode Amazon limits the number of messages you can send per day and only allows verified sender and recipient addresses. You can verify addresses from the SES console.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Production mode&lt;/strong&gt;
Once you want to switch to production you can request production access from within the SES console. Production mode raises the message limit per day and only requires verified sender addresses. You can also verify a whole domain as a sender domain.&lt;/p&gt;
</description>
        <pubDate>Wed, 15 May 2013 00:00:00 +0000</pubDate>
        <link>http://blog.philipp-rieber.net/2013/05/15/moving-to-the-cloud-part-5-enabling-ses/</link>
        <guid isPermaLink="true">http://blog.philipp-rieber.net/2013/05/15/moving-to-the-cloud-part-5-enabling-ses/</guid>
        
        
      </item>
    
      <item>
        <title>Moving to the cloud part 4: Enabling S3</title>
        <description>&lt;p&gt;Moving to the cloud mostly means moving to a scalable multi-server environement with a load balancer in front. The load balancer redirects a user to an available web server instance of the cluster. Imagine a form with an image file upload somewhere in your application allowing a user to publish an avatar on his profile page. Handling the uploaded file the old way would mean to store it on the current web server’s file system. But how could this file be accessed by other web servers of the cluster, e.g. to display the avatar in the user’s public profile to users that have been redirected to another instance of the cluster? Moreover, what happens if we want to scale down our multi-server environment – meaning that we may need to shut down a web server that stores uploaded images? One possible solution would be to setup an additional file server for this purpose, not being part of the scaling cluster. All webs servers could access uploaded files at the same central location. But there are several drawbacks with this setup: First, it means setting up and maintaining another server with a different configuration. Second, it means a single point of failure: if our single file server fails then the whole application is concerned – and for the sake of simplicity mirroring the file server is not an option… S3 to the rescue!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://aws.amazon.com/s3&quot;&gt;Amazon S3&lt;/a&gt; (Simple Storage Service) is a cloud storage: it allows you to store files on Amazon servers. Based on one of the most reliable infrastructures on the internet and with features like permissions and REST/SOAP APIs on top it should perfectly suit our needs for a centralized file storage. There are some nice S3 management tools which allow file handling similar to all the good old FTP clients, e.g. &lt;a href=&quot;http://s3browser.com/&quot;&gt;S3 Browser&lt;/a&gt; or &lt;a href=&quot;http://www.cloudberrylab.com/&quot;&gt;CloudBerry&lt;/a&gt;. But remember the file upload in our application: we will need to handle files programatically. The S3 documentation describes all the low level commands for file operations: how to upload or download files, how to setup permissions or how to list your existing files. If you do not want to reinvent the wheel you should use the appropriate standard development kit (SDK), abstracting away all the tedious work of crafting restful URLs and looking up all the parameters. Amazon provides SDKs for all major languages, e.g. the &lt;a href=&quot;http://aws.amazon.com/sdkforphp/&quot;&gt;AWS SDK for PHP&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But we didn’t wanted to tie our application completely to S3 by spreading SDK code everywhere, so we went one step further by using the fabulous &lt;a href=&quot;https://github.com/KnpLabs/Gaufrette&quot;&gt;Gaufrette library&lt;/a&gt; and its &lt;a href=&quot;https://github.com/KnpLabs/KnpGaufretteBundle&quot;&gt;Symfony2 bundle&lt;/a&gt;. Gaufrette provides a filesystem abstraction layer allowing us to handle files independently from the underlying storage system. In other words: our application will use Gaufrette commands to save and retrieve files without knowing the underlying filesystem: Local, FTP, S3, database, Dropbox, APC …&lt;/p&gt;

&lt;p&gt;Every installation of our application can be configured separately which filesystem to use. This allows us to continue working with the local filesystem in our development, staging or test environment without being charged by Amazon and to still be able to develop offline.&lt;/p&gt;

&lt;p&gt;Installing the AWS S3 SDK for PHP is as simply as adding a new line to your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;composer.json&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;require&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;amazonwebservices/aws-sdk-for-php&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;1.x&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;p&gt;Then update your vendors:&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;nv&quot;&gt;$ &lt;/span&gt;composer udpate amazonwebservices/aws-sdk-for-php&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Configure the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AmazonS3&lt;/code&gt; class from the AWS SDK as a service. Usually you’ll have to pass an options array with the S3 credentials as constructor arguments:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;c&quot;&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;service&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;my.storage.s3&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;AmazonS3&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;argument&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;collection&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;argument&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;key=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;%uploads_s3_key%&lt;span class=&quot;nt&quot;&gt;&amp;lt;/argument&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;argument&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;key=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;secret&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;%uploads_s3_secret%&lt;span class=&quot;nt&quot;&gt;&amp;lt;/argument&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/argument&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/service&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Add the credentials to your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parameters.yml&lt;/code&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;parameters&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# ...&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;uploads_s3_key&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;MyS3Key&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;uploads_s3_secret&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;MyS3Secret&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now you could grab the service from the container and just use it:&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;nv&quot;&gt;$s3&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;container&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;'my.storage.s3'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$s3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;create_object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'my-bucket-name'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'my-file'&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 mentioned above we can get rid of this dependency on the S3 service by using Gaufrette. Install the Gaufrette Symfony2 bundle by adding another line to your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;composer.json&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;require&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;knplabs/knp-gaufrette-bundle&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;0.1.x&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;p&gt;Update your vendors again:&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;nv&quot;&gt;$ &lt;/span&gt;composer udpate knplabs/knp-gaufrette-bundle&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Register the bundle in the kernel:&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;c1&quot;&gt;// app/AppKernel.php&lt;/span&gt;
&lt;span class=&quot;c1&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;registerBundles&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;$bundles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Knp\Bundle\GaufretteBundle\KnpGaufretteBundle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
        &lt;span class=&quot;c1&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;$bundles&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;// ...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The container configuration of the Gaufrette bundle allows to register different virtual filesystems in a so called filesystem map. Every filesystem requires an adapter for defining and configuring the underlying real storage. In our example we register a filesystem named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uploads&lt;/code&gt; and make its adapter configurable:&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;# app/config/config.yml&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# ...&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;knp_gaufrette&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;adapters&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# ...&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;filesystems&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;uploads&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;adapter&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;%uploads_adapter%&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Usage of a filesystem is easy. Just retrieve the desired filesystem from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;knp_gaufrette.filesystem_map&lt;/code&gt; service and use its self-explanatory methods to handle files:&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;c1&quot;&gt;// Get filesystem map&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$filesystemMap&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;container&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;'knp_gaufrette.filesystem_map'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Get filesystem&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$filesystem&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$filesystemMap&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;'uploads'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Write file&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$filesystem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;write&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;$content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Read file&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$filesystem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;read&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;c1&quot;&gt;// Delete file&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$filesystem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;delete&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;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;But how to define and switch the adapters? This also happens in the container configuration:&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;# app/config/config.yml&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# ...&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;knp_gaufrette&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;adapters&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;uploads_local&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;directory&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;%uploads_local_directory%&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;uploads_s3&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;amazon_s3&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;amazon_s3_id&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;my.storage.s3&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Service ID for AmazonS3 class, see above&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;bucket_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;%uploads_s3_bucket_name%&quot;&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;region&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;%uploads_s3_region%&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;filesystems&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# ...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The first adapter &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uploads_local&lt;/code&gt; defines a simple local filesystem with only one parameter: the directory where the files should be stored. The second adapter &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uploads_s3&lt;/code&gt; defines what we were waiting for: S3 storage. We have to specify the service key of the above configured AmazonS3 service and additionally pass a bucket name and the appropriate &lt;a href=&quot;http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region&quot;&gt;AWS region&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now we can complete our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parameters.yml&lt;/code&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;parameters&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# ...&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;uploads_adapter&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;uploads_local&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# uploads_local|uploads_s3&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;uploads_local_directory&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;%kernel.root_dir%/../web/uploads&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;uploads_s3_key&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;MyS3Key&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;uploads_s3_secret&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;MyS3Secret&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;uploads_s3_region&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;s3-eu-west-1.amazonaws.com&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;uploads_s3_bucket_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;my-bucket-name&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;By switching the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uploads_adapter&lt;/code&gt; value between &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uploads_local&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uploads_s3&lt;/code&gt; we can now switch between local file storage and S3 storage.&lt;/p&gt;
</description>
        <pubDate>Sat, 11 May 2013 00:00:00 +0000</pubDate>
        <link>http://blog.philipp-rieber.net/2013/05/11/moving-to-the-cloud-part-4-enabling-s3/</link>
        <guid isPermaLink="true">http://blog.philipp-rieber.net/2013/05/11/moving-to-the-cloud-part-4-enabling-s3/</guid>
        
        
      </item>
    
      <item>
        <title>Moving to the cloud part 3: Enabling Route 53</title>
        <description>&lt;p&gt;This is part 3 of &lt;a href=&quot;/2013/03/09/moving-to-the-cloud-part-1-intentions/&quot;&gt;my series of articles&lt;/a&gt; about our first application move to the Amazon Cloud. As we are not the owner of the productive domain of the application, all communication about DNS changes has always been quite tedious, time consuming and prone to errors in the past – especially when your contact person lives in another time zone. In preparation to the final application move to EC2, which involves some DNS changes to switch to the Amazon load balancer, we wanted to gain some flexibility. Enter Route 53.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://aws.amazon.com/route53/&quot;&gt;Route 53&lt;/a&gt; allows you to manage all the DNS records of a given domain – even if you are not the owner of the domain. For instance, you can route a domain or any subdomain at any time to any server of your choice. This is quite cool because whenever we’ll be ready with the setup of our EC2 server cluster we ourselves will be able to flip the switch. No need to contact someone, no need to wait impatiently for the changes to happen. If something goes wrong – let’s do a rollback to the previous setup.&lt;/p&gt;

&lt;p&gt;To let Route 53 take over control your domain’s DNS we just have to change the nameserver records to Amazon’s nameservers. Go to the &lt;a href=&quot;https://console.aws.amazon.com/route53&quot;&gt;Route 53 console&lt;/a&gt;, create a new hosted zone, enter the domain name and save. After saving, the console lists the names of four Amazon nameservers.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/aws/route53-1.png&quot; alt=&quot;Route53-1&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You, your registrar or your client’s registrar will have to update your domain NS records with these nameservers. In our case we had to ask our client’s registrar to do this. But wait! As we are dealing with a productive application we should put the existing DNS configuration in place before requesting the nameserver switch – otherwise our application would not be accessible any more. Having our application running at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;myapp.onemedia.de&lt;/code&gt; and the code be hosted at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;192.51.100.234&lt;/code&gt; we would just have to create an appropriate A record:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/aws/route53-2.png&quot; alt=&quot;Route53-2&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/aws/route53-3.png&quot; alt=&quot;Route53-3&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now we have some kind of shadow configuration, i.e. we’ve created a clone of the existing live DNS configuration which is not yet in use. So we are prepared to switch the nameservers to Amazon and everything will just work as before – but then we are in control of the domain’s DNS records.&lt;/p&gt;

&lt;p&gt;Unfortunately something unexpected happend when we finally requested the nameserver switch at our client’s contact person. Along with replacing the nameservers the registrar also flushed the existing configuration – more precisely the A records we have also setup in Route 53. During the next hours we had lots of complaints about the application being offline and this was quite a painful situation. Moreover, reachability seemed to be quite arbitrary: some users had no issues while others were able to reach some of the subdomains only or even nothing at all. After thinking a while about what had happend we came to the conclusion that all the networks that requested the domain the day before the nameserver switch were not able to reach our application any more. The reason was the DNS cache of the network routers or the computers respectively. We could only wait for the time to live (TTL) of the nameserver records to expire and ask for understanding. Nonetheless, we learned our lesson for the next time and there are two possibilities what needs to be communicated to the registrar:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Replace the nameserver records but leave the current configuration in place for at least one day&lt;/li&gt;
  &lt;li&gt;Reduce the TTL for the nameserver records one or two days in advance – then change the nameserver records and flush the configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After about 18 hours everything was back to normal and we were happy to announce our first Amazon webservice to be live: Route 53&lt;/p&gt;
</description>
        <pubDate>Mon, 18 Mar 2013 00:00:00 +0000</pubDate>
        <link>http://blog.philipp-rieber.net/2013/03/18/moving-to-the-cloud-part-3-enabling-route-53/</link>
        <guid isPermaLink="true">http://blog.philipp-rieber.net/2013/03/18/moving-to-the-cloud-part-3-enabling-route-53/</guid>
        
        
      </item>
    
  </channel>
</rss>
