<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Flex on Guillaume Delré</title><link>https://guillaumedelre.github.io/tags/flex/</link><description>Recent content in Flex on Guillaume Delré</description><generator>Hugo</generator><language>en</language><lastBuildDate>Sun, 14 Jan 2018 00:00:00 +0000</lastBuildDate><atom:link href="https://guillaumedelre.github.io/tags/flex/index.xml" rel="self" type="application/rss+xml"/><item><title>Symfony 4.0: Flex and the end of the Standard Edition</title><link>https://guillaumedelre.github.io/2018/01/14/symfony-4.0-flex-and-the-end-of-the-standard-edition/</link><pubDate>Sun, 14 Jan 2018 00:00:00 +0000</pubDate><guid>https://guillaumedelre.github.io/2018/01/14/symfony-4.0-flex-and-the-end-of-the-standard-edition/</guid><description>Part 3 of 11 in &amp;quot;Symfony Releases&amp;quot;: Symfony 4.0 killed the Standard Edition and introduced Flex: a microframework that grows only as far as you actually need.</description><category>symfony-releases</category><content:encoded><![CDATA[<p>Symfony 4.0 released November 30, 2017, same day as 3.4. The shared release date is pretty much the only thing they have in common.</p>
<p>4.0 is a different philosophy. The Symfony Standard Edition, the monolithic starting point that bundled everything and left you to remove what you didn&rsquo;t need, is gone. In its place: a microframework that grows.</p>
<h2 id="flex">Flex</h2>
<p>Symfony Flex is a Composer plugin that changes how you install Symfony packages. Before Flex, adding a bundle meant: install via Composer, register in <code>AppKernel.php</code>, add config to <code>config/</code>, update routing if needed. Four steps, all manual.</p>
<p>With Flex, installing a package runs a &ldquo;recipe&rdquo;: a set of automated steps that registers the bundle, generates a config skeleton, and wires routing. Installing Doctrine:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>composer require symfony/orm-pack
</span></span></code></pre></div><p>That command installs the packages, creates <code>config/packages/doctrine.yaml</code>, adds the env variable stubs to <code>.env</code>, and registers everything. One command, zero manual steps.</p>
<p>Recipes are community-contributed and hosted on a central server. Quality varies, but for major packages they&rsquo;re maintained alongside the packages themselves.</p>
<h2 id="the-new-project-structure">The new project structure</h2>
<p>The Standard Edition layout (<code>app/</code>, <code>src/</code>, <code>web/</code>) is replaced by a leaner structure. Config lives in <code>config/</code> split by environment. The public directory is now <code>public/</code>, not <code>web/</code>. The kernel is smaller. Controllers are plain classes, no <code>extends Controller</code> required.</p>
<p>More importantly, the default <code>services.yaml</code> uses the 3.3 autowiring defaults that make explicit service configuration mostly unnecessary. New projects start minimal and grow by adding what they actually need.</p>
<h2 id="services-private-by-default">Services private by default</h2>
<p>4.0&rsquo;s biggest BC break for existing apps: all services are private by default. You can&rsquo;t fetch a service from the container directly anymore, it has to be injected. This is the right call from a DI perspective, but it breaks anything that used <code>$this-&gt;get('service_id')</code> in controllers.</p>
<p>The migration path is <code>AbstractController</code>, which provides the same convenience methods through lazy service locators rather than raw container access.</p>
<h2 id="what-was-removed">What was removed</h2>
<p>4.0 is clean because it removes everything deprecated in 3.4:</p>
<ul>
<li>The old form events, the old security interfaces, the old configuration formats</li>
<li>Support for PHP &lt; 7.1.3</li>
<li>The ClassLoader component</li>
<li>ACL support from SecurityBundle</li>
</ul>
<p>The removals are aggressive. Apps that skipped fixing their 3.4 deprecations will have a rough time. Apps that did the cleanup beforehand have a smooth path.</p>
<p>Symfony 4.0 is the reset the framework needed. The Standard Edition had accumulated years of &ldquo;this is how it&rsquo;s done&rdquo; that Flex sweeps away in one shot.</p>
<h2 id="environment-variables-that-actually-know-their-type">Environment variables that actually know their type</h2>
<p>Before 3.4 and 4.0, environment variables were strings. Always. Trying to inject <code>DATABASE_PORT</code> into an <code>int</code> parameter would silently break or blow up with a type error. The fix was ugly: cast in PHP or avoid typed parameters entirely.</p>
<p>4.0 ships with env var processors that handle the conversion at the container level:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">parameters</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">app.connection.port</span>: <span style="color:#e6db74">&#39;%env(int:DATABASE_PORT)%&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">app.debug_mode</span>: <span style="color:#e6db74">&#39;%env(bool:APP_DEBUG)%&#39;</span>
</span></span></code></pre></div><p>Beyond casting, processors can decode base64, load from files, parse JSON, or resolve container parameters within a value. The <code>json:file:</code> combination turned into a clean pattern for loading secrets from mounted files in containerized deployments:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">parameters</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">env(SECRETS_FILE)</span>: <span style="color:#e6db74">&#39;/run/secrets/app.json&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">app.secrets</span>: <span style="color:#e6db74">&#39;%env(json:file:SECRETS_FILE)%&#39;</span>
</span></span></code></pre></div><p>You can also write custom processors by implementing <code>EnvVarProcessorInterface</code> and tagging the service. Looks like overkill until the day you need it.</p>
<h2 id="tagged-services-without-the-boilerplate">Tagged services without the boilerplate</h2>
<p>Before 4.0, collecting all services with a given tag into one service meant writing a compiler pass. Forty lines of PHP to say &ldquo;give me everything tagged <code>app.handler</code>.&rdquo;</p>
<p>3.4 introduced the <code>!tagged</code> YAML shorthand, and 4.0 carries it forward:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">services</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">App\HandlerCollection</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">arguments</span>: [!<span style="color:#ae81ff">tagged app.handler]</span>
</span></span></code></pre></div><p>The collection is lazy by default when type-hinted as <code>iterable</code>, so services aren&rsquo;t instantiated until you actually iterate. This replaced a whole category of compiler passes that existed for the sole purpose of building lists.</p>
<h2 id="php-as-a-configuration-format">PHP as a configuration format</h2>
<p>YAML has been the default for so long it feels required. It isn&rsquo;t. 4.0 ships with PHP-based configuration using a fluent interface:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#75715e">// config/services.php
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">return</span> <span style="color:#66d9ef">function</span> (<span style="color:#a6e22e">ContainerConfigurator</span> $container) {
</span></span><span style="display:flex;"><span>    $services <span style="color:#f92672">=</span> $container<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">services</span>()
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">defaults</span>()
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">autowire</span>()
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">autoconfigure</span>();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    $services<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">load</span>(<span style="color:#e6db74">&#39;App\\&#39;</span>, <span style="color:#e6db74">&#39;../src/&#39;</span>)
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">exclude</span>(<span style="color:#e6db74">&#39;../src/{Entity,Repository}&#39;</span>);
</span></span><span style="display:flex;"><span>};
</span></span></code></pre></div><p>Same approach works for routes. The practical benefit: IDE autocompletion, type checking, and actual PHP logic in configuration without the <code>%</code> parameter interpolation syntax. YAML isn&rsquo;t going anywhere, but now you have a choice.</p>
<h2 id="argon2i-because-bcrypt-was-already-aging">Argon2i, because bcrypt was already aging</h2>
<p>Symfony 3.4/4.0 added Argon2i support, winner of the 2015 Password Hashing Competition. Configuration is one line:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">security</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">encoders</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">App\Entity\User</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">algorithm</span>: <span style="color:#ae81ff">argon2i</span>
</span></span></code></pre></div><p>Argon2i is built into PHP 7.2+ and available via the sodium extension on earlier versions. Like bcrypt, it&rsquo;s self-salting, no need to manage salt columns. Unlike bcrypt, it&rsquo;s designed to resist GPU-based attacks with configurable memory usage. If you&rsquo;re starting a new project on 4.0, there&rsquo;s really no reason to reach for bcrypt.</p>
<h2 id="the-form-layer-gets-a-bootstrap-4-theme">The form layer gets a Bootstrap 4 theme</h2>
<p>The existing Bootstrap 3 form theme has been around since Symfony 2.x. Bootstrap 4 ships as a first-class option in 4.0:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">twig</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">form_themes</span>: [<span style="color:#e6db74">&#39;bootstrap_4_layout.html.twig&#39;</span>]
</span></span></code></pre></div><p>More useful in practice: the <code>tel</code> and <code>color</code> HTML5 input types are now available as <code>TelType</code> and <code>ColorType</code> form types. Before, you had to write custom types or override raw widgets for those.</p>
<h2 id="local-service-binding">Local service binding</h2>
<p>Global <code>_defaults</code> bindings apply to all services. Sometimes you need a binding scoped to a specific class or namespace, like different logger instances for different subsystems.</p>
<p>4.0 supports per-service <code>bind</code> for exactly that:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">services</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">App\Service\OrderService</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">bind</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">Psr\Log\LoggerInterface</span>: <span style="color:#e6db74">&#39;@monolog.logger.orders&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">App\Service\PaymentService</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">bind</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">Psr\Log\LoggerInterface</span>: <span style="color:#e6db74">&#39;@monolog.logger.payments&#39;</span>
</span></span></code></pre></div><p>Same interface, two different implementations, no factory, no extra configuration. Small feature, but it kills a whole category of awkward workarounds.</p>
]]></content:encoded></item></channel></rss>