<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Fabien Potencier</title>
    <subtitle>Fabien Potencier&#039;s Blog</subtitle>
    <link href="http://fabien.potencier.org/feed/index.atom" rel="self" />
    <link href="http://fabien.potencier.org/" />    <id>http://fabien.potencier.org/</id>    <updated>2020-03-21T00:00:00+01:00</updated>    <entry>
        <title>Week 1</title>        <id>http://fabien.potencier.org/week-1.html</id>        <updated>2020-03-21T00:00:00+01:00</updated>
        <author>
            <name>Fabien Potencier</name>
            <email>fabien.potencier@gmail.com</email>
        </author>
        <link rel="alternate" type="text/html" href="http://fabien.potencier.org/week-1.html"/>        <summary>First week of confinement.
</summary>        <content type="html" xml:lang="en"><![CDATA[<p>This is my first "lockdown" week-end after a week of confinement. I'm not alone.
Most of us are confined now. Most of the world is confined or will be very soon.</p>
<p>I won't go outside this week-end and that's fine.</p>
<p>I'm lucky. I share my life with my wife and my two sons in my apartment in Lille, France.
Hopefully, we're not infected. Not yet. We're now following the rules very strictly. To protect us, but
more importantly, to protect everyone else. Let's not be selfish.</p>
<p>In January and February, the weather was bad. It rained every single day. Or it seemed so.
Since the beginning of the week, sun made a big come back.
The sun taunts me. If you know me a little, you know that I would really like to go outside.
Buy a book in my local bookstore, buy some groceries, find some new cheese to taste,
bike to the butcher, jog in the biggest public park of the city. I would love to do all of these activities today.
Like every "regular" Saturday. But for the next few weeks, my world will look different. I need to adapt.
And that's fine. I can certainly wait.</p>
<p>I'm lucky. I can work from home. My sons are 12 and 15, so they can do their homework on their own.
Wonderful kids. They know how to spend their time. They read books, they watch some episodes
of their favorite series on TV. They draw and they are talented. Don't ask me to draw anything.</p>
<p>I'm lucky. I'm the CEO of two great companies. Symfony and Blackfire. Remote first companies. All
employees are working remotely, from home. They live everywhere in the world. I'm proud of them.
They are confined like everyone else. Some have kids at home. Some are anxious. We are all reading
the news, trying to understand what's going on; trying to imagine the impact of this "tornado".
We are also trying to keep working. As "usual". Let's be honest, maybe less than usual.
That's fine.
The business is impacted. Some customers have already canceled their subscription. Very little
new customers this week. That makes sense.
At Symfony, we're canceling or postponing all our worldwide conferences. At Blackfire,
our marketing is mostly about sponsoring conferences. All our eggs in the same basket. How ironic.
Everyone is on board to imagine our future. We have many ideas to reinvent ourselves. I'm blessed.</p>
<p>I'm lucky. I'm young-ish and I'm in good health. I want to help but I'm not a doctor. I'm trying to support my
family and my employees the best I can. There is blood shortage in France, and in some other countries.
I will donate my blood next week.</p>
<p>This is the week-end. I won't go outside. I will probably read fiction books and code. I will cook for sure. As usual.
But I will also take some time to dream. For a change. Or perhaps thinking about what's next.</p>
<p>Be strong, stay safe.</p>]]></content>
    </entry>    <entry>
        <title>Symfony 4: Unpack the Packs</title>        <id>http://fabien.potencier.org/symfony4-unpack-the-packs.html</id>        <updated>2018-01-04T00:00:00+01:00</updated>
        <author>
            <name>Fabien Potencier</name>
            <email>fabien.potencier@gmail.com</email>
        </author>
        <link rel="alternate" type="text/html" href="http://fabien.potencier.org/symfony4-unpack-the-packs.html"/>        <summary>Introducing a way to unpack the packs.
</summary>        <content type="html" xml:lang="en"><![CDATA[<p>We get a lot of positive feedback on Symfony 4. You love the new directory structure. You love the simplicity of using services without configuring anything. And you love the automation that Flex provides. It makes me happy and proud.</p>
<p>But one issue I hear sometimes is that it is more complex to start a new project. Most projects need many Symfony features. But new projects now have bare minimum dependencies when created via <code>composer create-project symfony/skeleton</code>. You need to explicitly add all the dependencies you want to depend on. Being explicit is great, but UX suffers. Ever tried to add <code>profiler</code> and didn't get timing info? Yup, <code>symfony/stopwatch</code> is optional, so you need to add it explicitly.</p>
<p>You loved the simplicity of starting a project with the Symfony Standard Edition. Is it nostalgia? Perhaps. Would it be possible to get the best of both world? Certainly! Read on.</p>
<p>First, let me recap some current available features:</p>
<ul>
<li>
<p>Any Composer package can have a related recipe that helps with
auto-configuration (recipes are stored at <code>symfony/recipes</code> and
<code>symfony/recipes-contrib</code>);</p>
</li>
<li>Symfony Packs are Composer metapackages that bundle several dependencies
together to make your life easier (install <code>symfony/debug-pack</code> and get
everything you need to debug a Symfony application).</li>
</ul>
<p>Symfony Packs are time savers, but they have one limitation: they mask the real dependencies. Let me explain with an example. Using <code>symfony/orm-pack</code> is a great way to get the most commonly needed Doctrine related packages and bundles. Run <code>composer req symfony/orm-pack</code> (or simply <code>composer req orm</code>) to get Doctrine core, the Doctrine bundle, and the Doctrine migrations bundle (everything configured thanks to some nice recipes).</p>
<p>But what if you want to remove one dependency that is included in the pack? Like the migrations bundle. You cannot remove it as the project's <code>composer.json</code> file requires <code>symfony/orm-pack</code>, not the individual dependencies:</p>
<pre><code class="language-diff">diff --git a/composer.json b/composer.json
index e24f26b..5238f98 100644
--- a/composer.json
+++ b/composer.json
@@ -7,6 +7,7 @@
         "symfony/flex": "^1.0",
         "symfony/framework-bundle": "^4.0",
         "symfony/lts": "^4@dev",
+        "symfony/orm-pack": "^1.0",
         "symfony/yaml": "^4.0"
     },
     "require-dev": {</code></pre>
<p>Another example would be when you want to change a dependency constraint for a package coming from a pack.</p>
<p>You can of course require the individual dependencies, but for packs like <code>debug</code> or <code>api</code>, you would have to have a look at their <code>composer.json</code> on Github and do some copy/paste. Not ideal.</p>
<p>There is another way. Unpacking the pack. You can now <code>unpack</code> an already installed pack via the <code>unpack</code> command:</p>
<pre><code class="language-bash">composer unpack orm</code></pre>
<p>The command updates <code>composer.json</code> to remove the pack and replace it with the individual dependencies defined in the pack:</p>
<pre><code class="language-diff">diff --git a/composer.json b/composer.json
index 5238f98..b8c9794 100644
--- a/composer.json
+++ b/composer.json
@@ -3,11 +3,13 @@
     "license": "proprietary",
     "require": {
         "php": "^7.1.3",
+        "doctrine/doctrine-bundle": "^1.6.10",
+        "doctrine/doctrine-migrations-bundle": "^1.3",
+        "doctrine/orm": "^2.5.11",
         "symfony/console": "^4.0",
         "symfony/flex": "^1.0",
         "symfony/framework-bundle": "^4.0",
         "symfony/lts": "^4@dev",
-        "symfony/orm-pack": "^1.0",
         "symfony/yaml": "^4.0"
     },
     "require-dev": {</code></pre>
<p>Tweaking the pack dependencies is now possible. Don't want the migration bundles? Simple enough:</p>
<pre><code class="language-bash">composer rem migrations</code></pre>
<p>You can also unpack a pack at installation time via the <code>--unpack</code> flag. That flag tells Composer to add the dependencies of the pack in your <code>composer.json</code> instead of adding the pack package itself:</p>
<pre><code class="language-bash">composer req orm-pack --unpack</code></pre>
<p>Note that the <code>unpack</code> command and the <code>--unpack</code> flag only work for Symfony packs (the Composer package type must be <code>symfony-pack</code>). Any other dependencies are simply ignored and follow the standard Composer installation process.</p>
<p>That's a great feature by itself and give you even more power when it comes to dependency management.</p>
<p>Now, you could create a "Symfony Standard Edition" pack and benefit from the new unpacking feature.</p>
<p>That would almost work. Except that the Symfony Standard Edition has dev dependencies that would not be installed by Composer. As you know, when adding a dependency, Composer will install any transitive dependencies from the <code>require</code> section, but it does not care about the ones defined under the <code>require-dev</code> section.</p>
<p>To get to the next level, and because you can now unpack a pack very easily, a Standard Edition can be re-created simply by having a new skeleton.</p>
<p>To demonstrate how that works, let's take the brand new <a href="https://github.com/symfony/website-skeleton/blob/4.0/composer.json">"Symfony Website Skeleton"</a> as an example.</p>
<p>This new skeleton <em>almost</em> replicates Symfony Standard Edition's dependencies:</p>
<pre><code class="language-json">{
    "name": "symfony/website-skeleton",
    "type": "project",
    "license": "MIT",
    "description": "A skeleton to start a new Symfony website",
    "require": {
        "php": "^7.1.3",
        "ext-iconv": "*",
        "sensio/framework-extra-bundle": "^5.1",
        "symfony/asset": "^4.0",
        "symfony/browser-kit": "^4.0",
        "symfony/console": "^4.0",
        "symfony/css-selector": "^4.0",
        "symfony/debug-pack": "*",
        "symfony/expression-language": "^4.0",
        "symfony/flex": "^1.0",
        "symfony/framework-bundle": "^4.0",
        "symfony/form": "^4.0",
        "symfony/lts": "^4@dev",
        "symfony/orm-pack": "*",
        "symfony/monolog-bundle": "^3.1",
        "symfony/process": "^4.0",
        "symfony/security-bundle": "^4.0",
        "symfony/serializer-pack": "*",
        "symfony/validator": "^4.0",
        "symfony/swiftmailer-bundle": "^3.1",
        "symfony/web-link": "^4.0",
        "symfony/webpack-encore-pack": "*",
        "symfony/yaml": "^4.0"
    },
    "require-dev": {
        "symfony/dotenv": "^4.0",
        "symfony/maker-bundle": "^1.0",
        "symfony/phpunit-bridge": "^4.0",
        "symfony/profiler-pack": "*"
},
...</code></pre>
<p>Run <code>composer create-project symfony/website-skeleton</code> to start a new project. You get everything you need to get started fast. Use the <code>unpack</code> command if you need greater control over the added dependencies; unpack, remove, add as you see fit. You have full control. Note that if you unpack a dependency defined under <code>require-dev</code>, all its dependencies are added to the <code>require-dev</code> section as expected.</p>
<p>Like Silex ? Start with <code>symfony/skeleton</code>. Like the full-stack Symfony framework better? Start with <code>symfony/website-skeleton</code>. Then, be free to add or remove dependencies. Scale the way <em>you</em> want your project.</p>
<p>Packs makes it easy to create great skeletons. And unpack allows to keep the flexibility of being explicit and precise about the dependencies.</p>
<p>The new unpack feature opens a lot of possibilities and gives you even more flexibility and control on your project's dependency management. Mind blowing if you ask me.</p>
<p>Happy Symfony!</p>]]></content>
    </entry>    <entry>
        <title>Symfony 4: Performance out of the Box</title>        <id>http://fabien.potencier.org/symfony4-performance.html</id>        <updated>2017-12-11T00:00:00+01:00</updated>
        <author>
            <name>Fabien Potencier</name>
            <email>fabien.potencier@gmail.com</email>
        </author>
        <link rel="alternate" type="text/html" href="http://fabien.potencier.org/symfony4-performance.html"/>        <summary>What about Symfony 4 performance? We worked on specific performance improvements for Symfony 4, but several non-performance related core changes help with performance as well.
</summary>        <content type="html" xml:lang="en"><![CDATA[<p>Performance is an interesting and sensitive topic. Suffice to say that most projects should not care too much; modern PHP frameworks are fast enough for most use cases and projects. And PHP 7 performance improvements help a lot as well. But people like to compare frameworks, and I guess performance is one way to do so.</p>
<p>What about Symfony 4? During its development cycle, we did some nice performance optimizations: mainly to improve the router and container speed. But several non-related changes in Symfony 4 also help with performance... Your mileage may vary depending on your specific project of course.</p>
<p>Synthetic benchmarks that were made to back pull requests that claimed to improve performance do not always convert to gain on real-world projects. Now that Symfony 4 is out, it's time to test a full project. An "Hello World!" application benchmark is a good start as it helps understand <strong>the base performance of a framework</strong>. It helps understand the overhead added on top of PHP by your framework of choice. We spent so much time doing optimizations that I wanted to compare the out-of-the-box performance of a default Symfony Standard Edition project (based on Symfony 3) with the performance of a Symfony 4 project.</p>
<p>Benchmarking is a science and takes a lot of time. Luckily enough, and while I was procrastinating, someone did the work for me. The <code>http://www.phpbenchmarks.com/en</code> website has a great benchmark protocol and a great UI that let you browser and compare results easily.</p>
<p>According to those benchmarks, an "hello world" page on Symfony 4.0 is almost <strong>twice as fast</strong> as the same code using Symfony 3.4. You read that right. On PHP 7.2, Symfony 4.0 is twice as fast compared to Symfony 3.4.</p>
<p>There is also a benchmark for a more complex REST API application. Symfony 4 is again still much faster than 3.4.</p>
<p>Visit <a href="http://www.phpbenchmarks.com/en"></a><a href="http://www.phpbenchmarks.com/en">http://www.phpbenchmarks.com/en</a> to get more numbers. Among other things, you will learn the following:</p>
<ul>
<li>
<p>Symfony on PHP 7.2 makes your code quite a bit faster than 7.1;</p>
</li>
<li>
<p>Symfony 2.3 is the <a href="http://www.phpbenchmarks.com/en/comparator/compare.html?components=symfony-2.3%7Esymfony-2.4%7Esymfony-2.5%7Esymfony-2.6%7Esymfony-2.7%7Esymfony-2.8%7Esymfony-3.0%7Esymfony-3.1%7Esymfony-3.2%7Esymfony-3.3%7Esymfony-3.4%7Esymfony-4.0&benchmarkType=all&benchmarkTools=apache-bench&phpVersions=php-7.2&concurrencies=">second fastest Symfony release</a> since 2.0</p>
</li>
<li>
<p>Symfony 3.4 is the slowest release since 2.0 (deprecated features are probably one of the reasons);</p>
</li>
<li>Symfony 4.0 is almost three times faster as Laravel 5.5.</li>
</ul>
<p>I would love to get some numbers for your application. Share them if you upgraded recently.</p>
<p>Enjoy using Symfony 4.0, the fastest Symfony ever released!</p>]]></content>
    </entry>    <entry>
        <title>Symfony Flex Private Repositories</title>        <id>http://fabien.potencier.org/symfony4-flex-private-repositories.html</id>        <updated>2017-11-23T00:00:00+01:00</updated>
        <author>
            <name>Fabien Potencier</name>
            <email>fabien.potencier@gmail.com</email>
        </author>
        <link rel="alternate" type="text/html" href="http://fabien.potencier.org/symfony4-flex-private-repositories.html"/>        <summary>Private recipes repositories support added to the Symfony Flex server.
</summary>        <content type="html" xml:lang="en"><![CDATA[<p><strong>Private Repositories are not available anymore by lack of interest. This blog post is kept for history but it is obsolete.</strong></p>
<p>Many Flex early adopters asked for it. The Symfony Flex server now supports private recipes repositories as announced during my keynote at SymfonyCon Cluj.</p>
<p>Creating a repository for your private recipes is easy. Create a regular Github repository (probably a private one) to store the recipes. The directory structure is the same as for the <a href="https://github.com/symfony/recipes">official Flex recipes repositories</a>. Then, <del>register the repository as a recipes repository</del> (not available anymore). Done.</p>
<p>After registration, the repository will behave in the exact same way as the official ones, with the same features like automatic validation of pull requests by the Flex bot, and a dedicated endpoint to test a pull request on a project.</p>
<p>As for the main recipes repository, but unlike the contrib one, private repositories can define aliases and override existing ones. Your aliases take precedence over the official ones. If you don't like our default choice for the <code>admin</code> or <code>orm</code> aliases, override them. You can also override a recipe to customize the package's default configuration.</p>
<p>There are some differences with the public repositories though: of course, you can define recipes for your private packages. Auto-merge of pull requests is not supported yet. And for Makefile lovers, I have some good news: private repositories support Makefile (as you have full control of your stack).</p>
<p>How do you configure the projects that can have access to your private repository? In a <code>config.json</code> file located at the root directory of the repository. Under the <code>projects</code> key, list the project's ULID (as found in <code>composer.json</code> or via <code>composer config extra.symfony.id</code>):</p>
<pre><code class="language-json">{
    "projects": {
        "01BWTQ6H4KJFHRZ240CXBN6S6A": "my super secret project",
        "01BYV69F2S7ECNN3N76K82BV4W": "demo"
    }
}</code></pre>
<p>While in beta, private repositories are free.</p>
<p>Happy private Flex!</p>]]></content>
    </entry>    <entry>
        <title>Symfony 4: An Update on Flex</title>        <id>http://fabien.potencier.org/symfony4-flex-update.html</id>        <updated>2017-11-21T00:00:00+01:00</updated>
        <author>
            <name>Fabien Potencier</name>
            <email>fabien.potencier@gmail.com</email>
        </author>
        <link rel="alternate" type="text/html" href="http://fabien.potencier.org/symfony4-flex-update.html"/>        <summary>A quick update on recent changes in Symfony Flex.
</summary>        <content type="html" xml:lang="en"><![CDATA[<p>Symfony 4 is just around the corner. And Symfony Flex is one of the main selling points for the upgrade. Developers love the new philosophy. And a lot of changes happened since my last blog post. Let me recap the recent changes that you might not be aware of. Most of these changes were prompted by feedback from early adopters.</p>
<p>Using recipes from the <a href="https://github.com/symfony/recipes-contrib">contrib repository</a> has became easier. The first time you require a package for which a contrib recipe exists, Flex now asks you the permission to execute the recipe. It also lets you switch the "accept contrib recipes" flag for the project (so it does not ask the question again). Much better experience, and better discoverability.</p>
<p>One issue people have had a lot is recipes installed multiple-times. I thought Flex got you covered except under some rare circumstances, but apparently those rare conditions are a bit more frequent than I anticipated. So, instead of trying to make clever hooks into the Composer life-cycle to determine if a recipe should be applied or not, each project now has a <code>symfony.lock</code> file where Flex's state is stored (this file must be committed in the project's code repository). Problem solved. And that lock file opens up some nice opportunities... but that's for another iteration.</p>
<p>Makefile support proves to be a nightmare. Despite several patches to the recipes having some Makefile support (support for Windows and whatnot), it was a never ending battle. At the end of the day, we realize that people had wrong expectations about the Makefile, and that <code>make</code> is not so standard. Instead of fighting the tool, we decided to add <code>symfony/console</code> as a requirement. Done. Simple. Efficient. And yes, Makefile support was introduced just as a facade to the optional Symfony Console component. You can still use a Makefile for your project of course. And I still think that this is a good idea.</p>
<p>The minimum version supported by Flex is now PHP 7.0 instead of PHP 7.1 previously to let more people use Flex. It's especially important for projects using Symfony 3.4, which is a long term support release. That will make the upgrade path to Symfony 4 smoother as well.</p>
<p>Having beta testers helped find bugs you would never have expected. When upgrading Flex, people had weird issues. That was because of how Composer plugins work. Some Flex classes are loaded early on by Composer. And if down the road, Flex is updated, you can have a situtation where a class from the newest version is mixed with classes from the old version. Not a good situation to be in. Now, Flex loads all its classes preemptively to be sure it is always in a consistent state.</p>
<p>In terms of features, Flex is now able to auto-register almost any bundle for which there are no recipes. And we added support for environment variables in PHPUnit configuration. Using Flex is also much faster as there are less roundtrips with the server (only one request per Composer session most of the time).</p>
<p>Regarding documentation, we have also started to document the new workflow with updates to the <a href="https://symfony.com/doc/4.0/setup/flex.html">upgrade tutorial</a> and the <a href="https://symfony.com/doc/4.0/best_practices/creating-the-project.html">best practices document</a>. They now take into account changes introduced by Flex. However, keep in mind that documentation updates are still on-going.</p>
<p>Last, but not least, the Symfony Flex Server has a new UI, which allows you to better discover available recipes, aliases, and packs.</p>
<p>Happy Flex!</p>]]></content>
    </entry>    <entry>
        <title>Symfony 4: Directory Structure Updates</title>        <id>http://fabien.potencier.org/symfony4-directory-structure-updates.html</id>        <updated>2017-07-03T00:00:00+02:00</updated>
        <author>
            <name>Fabien Potencier</name>
            <email>fabien.potencier@gmail.com</email>
        </author>
        <link rel="alternate" type="text/html" href="http://fabien.potencier.org/symfony4-directory-structure-updates.html"/>        <summary>After a long discussion in the community, the directory structure was slightly changed.
</summary>        <content type="html" xml:lang="en"><![CDATA[<p>After <a href="https://github.com/symfony/flex/issues/56">a long discussion in the
community</a>, the directory structure
has been slightly changed.</p>
<p><code>etc/</code> was renamed to <code>config/</code>, and <code>web/</code> to <code>public/</code>. My blog posts about
Symfony 4 have just been updated to reflect these changes.</p>
<p>If you already have a project using Symfony Flex, upgrading is as simple as:</p>
<ul>
<li>Renaming <code>etc/</code> to <code>config/</code>;</li>
<li>Renaming <code>web/</code> to <code>public/</code>;</li>
<li>Updating your web server configuration to take into account the new <code>public/</code> directory;</li>
<li>Upgrading <code>symfony/flex</code> to the latest version;</li>
<li>Done.</li>
</ul>]]></content>
    </entry>    <entry>
        <title>Symfony 4: A quick Demo</title>        <id>http://fabien.potencier.org/symfony4-demo.html</id>        <updated>2017-05-02T00:00:00+02:00</updated>
        <author>
            <name>Fabien Potencier</name>
            <email>fabien.potencier@gmail.com</email>
        </author>
        <link rel="alternate" type="text/html" href="http://fabien.potencier.org/symfony4-demo.html"/>        <summary>Eager to test Symfony 4. At least, the current preview version? Let&#039;s do it
now.
</summary>        <content type="html" xml:lang="en"><![CDATA[<p>Time to test Symfony 4... or at least let's test the experience of developing
Symfony 4 projects with Symfony 3.3. Keep in mind that all the tools are in
preview mode. Features might evolve over time. I'm waiting for your feedback!
The first stable version of Symfony Flex will not be released before Symfony 4
at the end of November 2017. It gives the community plenty of time to discuss
the changes I have described in this series of blog posts.</p>
<h2 id="creating-a-new-project">Creating a new Project<a href="#creating-a-new-project" class="anchor">#</a></h2>
<p>The first step is to create a project. Currently, this needs to be done via
<code>composer create-project</code>. We might release a tool to bootstrap a project
faster.</p>
<p>Let's go:</p>
<pre><code class="language-bash">composer create-project "symfony/skeleton:^3.3" demo
cd demo</code></pre>
<p><code>3.3</code> is the only currently available version and uses the yet-to-be-released
Symfony 3.3. Versions like , <code>4.0</code>, <code>lts</code>, or <code>latest</code> will be available
later on (but not before the <a href="https://symfony.com/roadmap?version=4.0#checker">release of Symfony 4.0</a>
of course).</p>
<p>The command downloads the <a href="https://github.com/symfony/skeleton">Symfony
skeleton</a> which consists of just one
<code>composer.json</code> file.</p>
<p>Then, it extracts the file into the <code>demo</code> directory and automatically runs
<code>composer install</code>. <code>symfony/flex</code> is the first package to be installed so that
it can hook into the Composer process. When Composer installs (or updates)
other dependencies, Symfony Flex looks for an associated <em>recipe</em> on the
Symfony Flex server, and executes it. You can see Symfony Flex in action via
the logs it adds to the Composer output.</p>
<p><img src="/media/articles/2017-05-02-symfony4-quick-demo/flex-output.png" alt="Symfony Flex Output"></p>
<p>When finished, you should see a "What's next?" section that explains the
possible next steps, like running <code>make serve</code> to start the PHP built-in web
server. Before going further, go to the project's directory: <code>cd demo</code>.</p>
<p><img src="/media/articles/2017-05-02-symfony4-quick-demo/whats-next.png" alt="What's next?"></p>
<p><code>serve</code> is one of the tasks added to the local <code>Makefile</code>, as described in the
<a href="https://github.com/symfony/recipes/tree/master/symfony/framework-bundle/3.3"><code>symfony/framework-bundle</code></a>
recipe.</p>
<p>Note that some commands were automatically installed and run at the end of the
process:</p>
<p><img src="/media/articles/2017-05-02-symfony4-quick-demo/scripts.png" alt="Scripts"></p>
<p>Again, those scripts were added to the project's <code>composer.json</code> file as
defined by the <code>symfony/framework-bundle</code> recipe. The second script did not run
because the console tool (available via <code>symfony/console</code>) is not installed by
default (we will see how to "fix" this issue later on).</p>
<p>Now is a good time to initialize Git:</p>
<pre><code class="language-bash">git init
git add .
git commit -m "initial set of files"</code></pre>
<p>Using <code>git add .</code> works well as Symfony took care of creating a "good"
<code>.gitignore</code> file.</p>
<p>Remember that the skeleton only has one file, <code>composer.json</code>. Check the
<code>demo/</code> directory now; some more files have been created. Those files were
added by Symfony Flex based on the installed packages, as described in recipes.</p>
<p>Let's examine the directory structure now. Most files has been added because of
the <code>symfony/framework-bundle</code> dependency.</p>
<p>The <code>.env</code> file defines the <code>APP_ENV</code> and <code>APP_DEBUG</code> environment variables:</p>
<pre><code class="language-ini">###> symfony/framework-bundle ###
APP_ENV=dev
APP_DEBUG=1
APP_SECRET=ODtvoHW6pn3bE2rHgTa2MjkjwefzlsJH
###< symfony/framework-bundle ###</code></pre>
<p>The comments allows Symfony Flex to "manage" this section. This is useful when
those variables needs to be removed when the package is removed. If you remove
the comments, Symfony Flex will not be able to automatically manage these
variables anymore. Have a look at <code>.gitignore</code> for a similar example.</p>
<p>If you're curious, check <code>public/index.php</code>, the new web front controller.</p>
<p>The most interesting files are under <code>config/</code>. The main entry points are the
empty <code>container.yaml</code> and <code>routing.yaml</code> files; this is where you can add
services, parameters, and routes for your project. A default configuration has
been installed as well for <code>symfony/framework-bundle</code> under <code>config/packages/</code>.
Feel free to tweak installed configuration files or add more for your own needs.</p>
<p>Last, but not least, <code>FrameworkBundle</code> is now registered in <code>bundles.php</code>:</p>
<pre><code class="language-php">return [
    'Symfony\Bundle\FrameworkBundle\FrameworkBundle' => ['all' => true],
];</code></pre>
<p>Even if a bundle does not have a recipe, Symfony detects Composer packages with
the <code>symfony-bundle</code> type and automatically enable them for all environments.
This avoids the creation of recipes when registration is just a matter of
enabling the bundle.</p>
<p>The <code>src/</code> directory is where you can store your PHP classes. Under the <code>App\</code>
namespace as registered in <code>composer.json</code>. Note that this is where
<code>Kernel.php</code> was also installed as <code>App\Kernel</code>.</p>
<p>Now, it is time to install some new dependencies via Composer. Let's start by
adding a more powerful web server for your project:</p>
<pre><code class="language-bash">composer req webserver</code></pre>
<p>And install Symfony console support via:</p>
<pre><code class="language-bash">composer req cli</code></pre>
<p><strong>Note</strong>: <code>req</code> is a shortcut for <code>require</code> (the Composer CLI supports any
shortcut that is not ambiguous; use <code>rem</code> to remove a Package).</p>
<p><code>webserver</code> is an <strong>alias</strong> for <code>symfony/web-server-bundle</code>, and <code>cli</code> is an
alias for <code>symfony/console</code>. That works because Symfony Flex knows how to
convert those aliases into full package names: <code>cli</code> is equivalent to
<code>console</code>, which is equivalent to <code>symfony/console</code>. The <code>symfony/</code> prefix is
always optional. Try <code>composer req workflow</code> or <code>composer req ldap</code>.
<code>web-server-bundle</code> is too cumbersome, so use <code>webserver</code> or just <code>server</code>.</p>
<p>For Symfony dependencies, Symfony Flex also recognizes a few more versions than
the usual Composer ones, mainly <code>next</code>, <code>previous</code>, <code>lts</code>, and <code>stable</code> (they
don't all work yet though).</p>
<pre><code class="language-bash">composer req cli:next</code></pre>
<p>After executing <code>composer req cli</code>, notice how the <code>assets:install</code> command
automatically ran. The <code>bin/console</code> file has also been added to your project.</p>
<p><img src="/media/articles/2017-05-02-symfony4-quick-demo/scripts-with-console.png" alt="Scripts with Console"></p>
<p>Aliases work when removing dependency as well:</p>
<pre><code class="language-bash">composer rem cli</code></pre>
<p>... which also removes the <code>bin/console</code> binary (for fun, try this: <code>composer rem framework-bundle</code>).</p>
<p>Remember I wrote about the developer experience when installing a Symfony
bundle? Let's go wild and install something really "complex" like an admin
generator based on Doctrine. How many steps to make it work? It might be fewer
than you expect, and definitely more fun.</p>
<p>First, let's install <a href="https://github.com/javiereguiluz/EasyAdminBundle">EasyAdminBundle</a>:</p>
<pre><code class="language-bash">composer req admin</code></pre>
<p>Besides installing the admin generator bundle, it also installs all its
transitive dependencies and auto-configures them all: <code>TwigBundle</code>,
<code>SecurityBundle</code>, <code>FrameworkExtraBundle</code>, and <code>DoctrineBundle</code>.</p>
<p><code>admin</code> is a "generic" word. This is why I wrote about Symfony Flex recipes
being opinionated. There can only be one package aliased to <code>admin</code>. <code>orm</code> is
another generic word that is currently aliased to the Doctrine ORM.</p>
<p>Run the PHP built-in web-server via <code>make serve</code> or <code>bin/console server:start</code>
and go to <code>http://localhost:8000/admin/</code>. You should get an error as no
Doctrine entities exist yet. Let's create one in <code>src/Entity/Product.php</code>:</p>
<pre><code class="language-php">namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="product")
 */
class Product
{
    /**
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    public $id;

    /**
     * @ORM\Column(type="string", length=100)
     */
    public $name;

    /**
     * @ORM\Column(type="decimal", scale=2)
     */
    public $price;

    /**
     * @ORM\Column(type="text")
     */
    public $description;
}</code></pre>
<p>Tweak the database configuration in <code>.env</code>:</p>
<pre><code class="language-text">###> doctrine/doctrine-bundle ###
DB_URL=mysql://root@127.0.0.1:3306/symfony?charset=utf8mb4
###< doctrine/doctrine-bundle ###</code></pre>
<p>Run the following commands to initialize the database:</p>
<pre><code class="language-bash">./bin/console doctrine:database:create
./bin/console doctrine:schema:update --force</code></pre>
<p>Finally, add the <code>Product</code> entity to the list of entities managed by the admin
generator (<code>config/packages/easy_admin.yaml</code>):</p>
<pre><code class="language-yaml">easy_admin:
    entities:
        - App\Entity\Product</code></pre>
<p>Try <code>http://localhost:8000/admin/</code> again. If everything worked well, you should
be able to manage products.</p>
<p><img src="/media/articles/2017-05-02-symfony4-quick-demo/admin.png" alt="Admin Generator Interface"></p>
<p>Instead of installing an admin generator, have a look at this small screencast
where I'm using the <code>api</code> alias to bootstrap an API project quickly and easily:</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/o9N1nOYfAl4" frameborder="0" allowfullscreen></iframe>
<p>Here are some nice aliases you can try:</p>
<ul>
<li><code>sec-checker</code> to install the SensioLabs Security Checker;</li>
<li><code>req-checker</code> to install the Symfony requirements checks;</li>
<li><code>log</code> to install MonologBundle and all its dependencies;</li>
<li><code>template</code> for Twig;</li>
<li><code>mailer</code> for Swiftmailer;</li>
<li><code>profiler</code> for the profiler;</li>
<li>... you get the point :)</li>
</ul>
<p>As <code>symfony/symfony</code> is not required anymore, you get more fine-grained
dependencies, but it might be cumbersome to install each Symfony component one
by one. To ease the pain, I'm experimenting with a new concept: "packs". A pack
is nothing more than a regular Git repository registered on Composer that
contains a <code>composer.json</code> that references a set of related packages. As an
example, I have created a <a href="https://github.com/symfony/debug-pack"><code>debug-pack</code>
pack</a> that can be installed via
<code>composer req debug-pack</code>. Have a look at the <a href="https://github.com/symfony/orm-pack">ORM
pack</a> or the <a href="https://github.com/api-platform/api-pack">API
pack</a>. Imagine a <code>web-pack</code> that
references nothing in <code>composer.json</code> but is associated with a recipe that
installs a set of default files under <code>public/</code> like favicons, a <code>robots.txt</code>,
and so on. Nice? Imagine the same for Travis, Blackfire, or Docker. Or a pack
that installs the exact same dependencies as the current Symfony Standard
Edition? Your imagination is the limit. Compose your applications with
off-the-shelf packages, packs, and their associated recipes.</p>
<p>Symfony Flex enables <strong>distribution composition instead of inheritance</strong>. The
new way is easier, more flexible, and more powerful at the same time.</p>
<p>The first version of the Symfony Flex server is quite simple, but over time,
more features will be implemented.</p>
<p>Now, it is probably time for you to write some code. What about some
controllers and templates? Hold on. Even if you can do what you are used to,
Symfony 3.3 and Symfony 4.0 proposes a much smoother experience that you might
like better. This is a great topic for my next post about Symfony 4.</p>
<p>Remember that the recipes repositories at
<a href="https://github.com/symfony/recipes"></a><a href="https://github.com/symfony/recipes">https://github.com/symfony/recipes</a> and
<a href="https://github.com/symfony/recipes-contrib"></a><a href="https://github.com/symfony/recipes-contrib">https://github.com/symfony/recipes-contrib</a>
are also public now. Feel free to look around. And keep in mind that
what you see is experimental. Current choices might change.</p>]]></content>
    </entry>    <entry>
        <title>Symfony 4: Contributing Recipes</title>        <id>http://fabien.potencier.org/symfony4-contributing-recipes.html</id>        <updated>2017-04-18T00:00:00+02:00</updated>
        <author>
            <name>Fabien Potencier</name>
            <email>fabien.potencier@gmail.com</email>
        </author>
        <link rel="alternate" type="text/html" href="http://fabien.potencier.org/symfony4-contributing-recipes.html"/>        <summary>The Symfony Recipes are opinionated, but anyone can contribute.
</summary>        <content type="html" xml:lang="en"><![CDATA[<p>Symfony Flex is not Open-Sourced yet, but I can already feel the excitement in
the community. I have also received some feedback via Twitter, Slack, and email
during the last few days. That makes me really happy!</p>
<p>Everybody knows that I like to tease. Trying to build the momentum on something
you have been working on for months feels great. But the reality is a bit more
complex: I am still working on the first MVP of the infrastructure needed to
support Symfony Flex. To be honest, I'm probably working on something that is a
bit more than just an MVP.</p>
<p>The good news is that I'm almost there. The bad news is that some feedback made
me realize that some features I had on my todo list for later need to be part
of the first version. You know, that "one more feature" that will make Symfony
Flex the next killer application for the Symfony community.</p>
<p>People are worried about the opinionated recipe repository. Keep in mind that
one of the main goals of Symfony Flex is to automate your day-to-day workflow
for the happy path.</p>
<p>First, I want to reiterate that a package does not need to have a recipe to be
installed. The good old way of registering bundles manually and copy/pasting
some default configuration will still work fine... which is what everybody has
been doing for years. In other words, everything will be at least as easy to
install as it is now.</p>
<p>Then, for several reasons I explained in my previous post, I won't change my
mind about the official repository being opinionated. I talk to a lot of
developers and companies using Symfony, and many want "us" to make choices for
them. They don't want to test dozens of bundles to make an informed choice.</p>
<p>Finally, I need to reveal one more recipe configuration option that I did not
mention yet: <em>aliases</em>. Instead of using the regular Composer package name, a
recipe can list alternative shorter names. For instance, use <code>composer req cli</code>
instead of <code>composer req symfony/console</code>. You can imagine packages willing to
reserve the <code>admin</code>, <code>api</code>, or <code>orm</code> aliases. And of course, each alias can
only be linked to one Composer package.</p>
<p>Choices are good.</p>
<p>But what about having another recipe repository along side the main one? Well,
that feature was on my todo list for a future version. But I have decided to
include it now. For the first version. And I like it a lot.</p>
<p>Let's dive into the Symfony Flex recipe repositories. Instead of having just
one repository, Symfony Flex supports two.</p>
<p>Here is how it works:</p>
<ul>
<li>
<p>The "main" official repository, hosted at
<a href="https://github.com/symfony/recipes"></a><a href="https://github.com/symfony/recipes">https://github.com/symfony/recipes</a>
will be opinionated. Submissions will be reviewed carefully. They will need
approval from the Symfony core team (like pull requests on the main
<code>symfony/symfony</code> repository). We want the utmost quality and the <em>best</em>
developer experience.</p>
</li>
<li>The "contrib" repository, hosted at
<a href="https://github.com/symfony/recip
es-contrib"></a><a href="https://github.com/symfony/recipes-contrib">https://github.com/symfony/recipes-contrib</a> will not be opinionated. Curated by the community at large, most
submissions will be accepted.</li>
</ul>
<p>Other than the rules to accept submissions, the "main" and the "contrib"
repositories work in the exact same way, except for the following differences:</p>
<ul>
<li>
<p>Only the "main" repository can define aliases (that makes sense I suppose);</p>
</li>
<li>By default, Symfony Flex only searches recipes in the "main" repository.
Using the "contrib" repository is <em>opt-in</em>. Enable it by executing <code>composer config extra.symfony.allow-contrib true</code>.</li>
</ul>
<p>And packages can be promoted from the "contrib" repository to the "main" one as
well.</p>
<p>To maintain a high level of quality, I have also developed a set of validation
rules for recipes. When you submit a pull request on both repositories, the
Symfony Flex server runs a series of checks to ensure that your changes are
valid. Basic checks like validating the existence of the package on Packagist.
And more interesting ones like checking that two packages do not define the
same alias.</p>
<p><img src="/media/articles/2017-04-18-symfony4-contributing-recipes/flex-ci-ko.png" alt="Symfony Flex Pull Request Validation"></p>
<p>But more interesting, a dedicated staging Flex Server is built for every pull
request. That allows anyone to test the changes before they are merged into the
master/production branch of a repository.</p>
<p><img src="/media/articles/2017-04-18-symfony4-contributing-recipes/flex-ci-ok.png" alt="Symfony Flex Pull Pull Request Staging Server"></p>
<p>For instance, if you submit a pull request (number 42) on the "contrib"
repository that adds a recipe for package "foo/bar", install your new package
by defining the <code>SYMFONY_ENDPOINT</code> environment variable:</p>
<pre><code class="language-bash">SYMFONY_ENDPOINT=https://symfony.sh/r/contrib/42 composer req foo/bar</code></pre>
<p>If changes are submitted for "core" packages (like in
<code>symfony/framework-bundle</code>), using the environment variable even works with
<code>composer create-project</code>:</p>
<pre><code class="language-bash">SYMFONY_ENDPOINT=https://symfony.sh/r/main/42 composer create-project symfony/skeleton demo</code></pre>
<p>That's all for now. I hope that these last minute changes make you happy.</p>]]></content>
    </entry>    <entry>
        <title>Symfony 4: Automate your Workflow</title>        <id>http://fabien.potencier.org/symfony4-workflow-automation.html</id>        <updated>2017-04-13T00:00:00+02:00</updated>
        <author>
            <name>Fabien Potencier</name>
            <email>fabien.potencier@gmail.com</email>
        </author>
        <link rel="alternate" type="text/html" href="http://fabien.potencier.org/symfony4-workflow-automation.html"/>        <summary>Time to introduce Symfony Flex, Symfony 4 secret weapon. Learn more about
what it can do for you.
</summary>        <content type="html" xml:lang="en"><![CDATA[<p>Symfony 4's most "innovative" feature is the way it drives the day-to-day
application management. No more tedious copy/paste from README files. No more
boilerplate code. Automation to the max. On a curated list of Composer packages.</p>
<h2 id="symfony-flex">Symfony Flex<a href="#symfony-flex" class="anchor">#</a></h2>
<p>Symfony 4 is powered by Symfony Flex, a deceptively simple but powerful
Composer plugin. The <a href="https://github.com/symfony/skeleton">default Symfony
skeleton</a> only lists two main
dependencies: <code>symfony/flex</code> and <code>symfony/framework-bundle</code>. Everything else is
optional.</p>
<p>As you can imagine, most projects need more than <code>FrameworkBundle</code>. And
installing and configuring all packages and bundles by hand is error-prone,
tedious, and just plain boring. Even for the few dependencies that Symfony
Standard Edition depends on.</p>
<p>This is where Symfony Flex shines.</p>
<p>When you install a Composer package, Flex hooks into the installation process
to automate its integration into your project via pre-defined and
community-driven recipes. It works for any Composer packages, not just Symfony
bundles. If a recipe does not exist, you can still configure it the old way,
like you currently do.</p>
<p>Take <code>sensiolabs/security-checker</code> as an example. It works for any PHP
projects. But when installed on a project using Symfony Flex, it knows how to
run the checker whenever you run <code>composer install</code>.</p>
<p>The automation is implemented in a recipe that has a JSON manifest that
describes how to integrate the package into a Symfony application. Here is the
one for <code>sensiolabs/security-checker</code>:</p>
<pre><code class="language-json">{
    "copy-from-recipe": {
        "config/": "%CONFIG_DIR%/"
    },
    "composer-scripts": {
        "vendor/bin/security-checker security:check": "php-script"
    }
}</code></pre>
<p>Flex currently implements 9 "configurators" that helps automate the integration
of any PHP package into a Symfony application: <code>copy-from-recipe</code>,
<code>copy-from-package</code>, <code>bundles</code>, <code>env</code>, <code>container</code>, <code>makefile</code>,
<code>composer-scripts</code>, <code>gitignore</code>, and <code>post-install-output</code>.</p>
<h2 id="bundles">Bundles<a href="#bundles" class="anchor">#</a></h2>
<p>The <code>bundles</code> configurator enables bundles in your project by adding them
to the <code>bundles.php</code> file (and it removes them when you uninstall the dependency):</p>
<pre><code class="language-json">{
    "bundles": {
        "Symfony\\Bundle\\DebugBundle\\DebugBundle": ["dev", "test"],
        "Symfony\\Bundle\\MonologBundle\\MonologBundle": ["all"]
    }
}</code></pre>
<h2 id="configuration">Configuration<a href="#configuration" class="anchor">#</a></h2>
<p>Configuration can be added via the <code>copy-from-recipe</code> and <code>copy-from-package</code>
configurators: the former copies files from the recipe while the later copies
files from the Composer package itself.</p>
<pre><code class="language-json">{
    "copy-from-package": {
        "bin/check.php": "%BIN_DIR%/check.php"
    },
    "copy-from-recipe": {
        "config/": "%CONFIG_DIR%/",
        "src/": "%SRC_DIR%/"
    }
}</code></pre>
<h2 id="environment-variables">Environment Variables<a href="#environment-variables" class="anchor">#</a></h2>
<p>The <code>env</code> configurator knows how to add environment variables to the project's
<code>.env</code> and <code>.env.dist</code> files (and removes them when uninstalling the dependency):</p>
<pre><code class="language-json">{
    "env": {
        "APP_ENV": "dev",
        "APP_DEBUG": "1"
    }
}</code></pre>
<h2 id="makefile-tasks">Makefile Tasks<a href="#makefile-tasks" class="anchor">#</a></h2>
<p>The <code>makefile</code> configurator adds new tasks to the project's <code>Makefile</code> (and
removes them when uninstalling the dependency). Unlike other configurators,
there is no entry in the <code>manifest.json</code>. Just define tasks in a <code>Makefile</code>
file:</p>
<pre><code class="language-makefile">cache-clear:
    @test -f bin/console && bin/console cache:clear --no-warmup || rm -rf var/cache/*
.PHONY: cache-clear

cache-warmup: cache-clear
    @test -f bin/console && bin/console cache:warmup || echo "cannot warmup the cache (needs symfony/console)"
.PHONY: cache-warmup</code></pre>
<p><em>Note</em>: A previous version of this blog post described a previous version where
the post install output was defined in the <code>manifest.json</code> file.</p>
<h2 id="composer-scripts">Composer Scripts<a href="#composer-scripts" class="anchor">#</a></h2>
<p>The <code>composer.json</code> file defined in <code>symfony/skeleton</code> contains the following snippet:</p>
<pre><code class="language-json">{
    "scripts": {
        "auto-scripts": [
        ],
        "post-install-cmd": [
            "@auto-scripts"
        ],
        "post-update-cmd": [
            "@auto-scripts"
        ]
    }
}</code></pre>
<p>The <code>composer-scripts</code> configurator manages the special <code>@auto-scripts</code> section
by adding commands and scripts defined in recipes. Those are automatically run
on <code>composer install</code> and <code>composer update</code>:</p>
<pre><code class="language-json">{
    "composer-scripts": {
        "assets:install --symlink --relative %PUBLIC_DIR%": "symfony-cmd"
    }
}</code></pre>
<h2 id="gitignore"><code>.gitignore</code><a href="#gitignore" class="anchor">#</a></h2>
<p>The <code>.gitignore</code> configurator adds patterns to the <code>.gitignore</code> file. And like
for the other configurators, it knows how to clean up when you remove a package:</p>
<pre><code class="language-json">{
    "gitignore": [
        "/phpunit.xml"
    ]
}</code></pre>
<h2 id="post-install-output"><code>post-install-output</code><a href="#post-install-output" class="anchor">#</a></h2>
<p>If you want to display some next step actions when a package is installed, list
them via the <code>post-install-output</code> configurator. Like for the Makefile, the output
must be defined in a <code>post-install.txt</code>:</p>
<pre><code class="language-txt">Execute <fg=blue>make serve</> to run your application.</code></pre>
<p><em>Note</em>: A previous version of this blog post described a previous version where
the post install output was defined in the <code>manifest.json</code> file.</p>
<h2 id="full-example">Full Example<a href="#full-example" class="anchor">#</a></h2>
<p>The most "complex" manifest is currently the one for <code>symfony/framework-bundle</code>
and reads as follows:</p>
<pre><code class="language-json">{
    "bundles": {
        "Symfony\\Bundle\\FrameworkBundle\\FrameworkBundle": ["all"]
    },
    "copy-from-recipe": {
        "config/": "%CONFIG_DIR%/",
        "public/": "%PUBLIC_DIR%/",
        "src/": "%SRC_DIR%/"
    },
    "composer-scripts": {
        "make cache-warmup": "script",
        "assets:install --symlink --relative %PUBLIC_DIR%": "symfony-cmd"
    },
    "env": {
        "APP_ENV": "dev",
        "APP_DEBUG": "1",
        "APP_SECRET": "%generate(secret)%"
    },
    "gitignore": [
        ".env",
        "/public/bundles/",
        "/var/",
        "/vendor/"
    ]
}</code></pre>
<p>That's all. I have yet to find a case not covered by this small set of
configurators. Note that I might remove the <code>container</code> one as it is not used
anymore in the current set of recipes I have written so far.</p>
<h2 id="an-opinionated-repository">An Opinionated Repository<a href="#an-opinionated-repository" class="anchor">#</a></h2>
<p>The Symfony Flex recipe repository will be opinionated. The developer is free
to use any combinations of packages, but to be able to provide a good sensible
configuration, we need to make choices. We won't be able to support all
bundles, only a curated set of them. Which is probably a good thing as well.</p>
<p>Symfony doesn't make choices for you. And that makes sense. You know what you
need for your project. But with more than 3000 bundles to choose from,
selecting the right bundle from the ecosystem is far from being easy for
beginners. Want an admin generator? Currently, you need to choose between 26
different ones. And several are quite popular. Which one should I use?</p>
<p>Compare that to symfony1, where the admin generator was built-in. This is just
one example. Have a look at the number of Blog bundles, or API ones. The great
news is that the Symfony community is hard at work.</p>
<p>Along the years, Symfony became a very low-level framework, without batteries
included. Now that Symfony gives us a very powerful platform to work with, I
think we can work on being more opinionated again.</p>
<p>We should be giving more exposure to good bundles. In order to do that, we
would first need to define what "good" means. I can imagine some simple rules
like the license, or the number of opened bugs vs activity on the Git
repository, the amount of documentation, the number of contributors, whether it
is compatible with a large set of Symfony versions, and so on.</p>
<p>And of course, any bundle can still be installed the old way, without
auto-configuration.</p>
<h2 id="the-symfony-flex-server">The Symfony Flex Server<a href="#the-symfony-flex-server" class="anchor">#</a></h2>
<p>Besides being a Composer plugin, Symfony Flex also communicates with an HTTP
server to get up-to-date information about package recipes, aliases, and more.</p>
<p>Try <code>curl https://flex.symfony.com/recipes/sensiolabs/security-checker/4.0 | json_pp</code>.</p>
<p>Eager to try out Symfony Flex? Well, I will push everything to Github just in
time for the next blog post.</p>]]></content>
    </entry>    <entry>
        <title>Symfony 4: Directory Structure</title>        <id>http://fabien.potencier.org/symfony4-directory-structure.html</id>        <updated>2017-04-10T00:00:00+02:00</updated>
        <author>
            <name>Fabien Potencier</name>
            <email>fabien.potencier@gmail.com</email>
        </author>
        <link rel="alternate" type="text/html" href="http://fabien.potencier.org/symfony4-directory-structure.html"/>        <summary>Symfony 4 has a slightly reworked directory structure. Incremental
adjustments to support new features and best practices.
</summary>        <content type="html" xml:lang="en"><![CDATA[<p>Symfony 3 came with a slightly different directory structure than Symfony 2.
Symfony 4 will also come with a reworked directory structure. Mostly
incremental adjustments to support new features and best practices.</p>
<p>The Symfony 3 <a href="https://github.com/symfony/symfony-standard/issues/584#issuecomment-23148928">directory
structure</a>
introduced a more standard Unix-like directory structure, with less sub-directories.
Symfony 4 keeps going in that direction.</p>
<p>Using well-known directory names helps. Using <code>bin/</code>, <code>src/</code>, or <code>var/</code> was a
great step forward. Symfony 4 adds <code>etc/</code> in place of <code>app/</code>. It was proposed
for Symfony 3 but rejected for reasons that don't hold anymore.</p>
<p><strong>Update</strong>: The <code>etc/</code> has been changed to <code>config/</code> after a long discussion
with the community. The <code>web/</code> directory has also been changed to <code>public/</code>.
The blog posts about Symfony 4 have been updated to reflect these changes.</p>
<h2 id="tests-under-tests">Tests under <code>tests/</code><a href="#tests-under-tests" class="anchor">#</a></h2>
<p>Tests move to a top-level <code>tests/</code> directory. It was proposed before, it just
makes sense now that we have bundle-less applications. It also allows to
declare a specific test namespace for autoloading:</p>
<pre><code class="language-json">{
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "App\\Tests\\": "tests/"
        }
    }
}</code></pre>
<h2 id="templates-under-templates">Templates under <code>templates/</code><a href="#templates-under-templates" class="anchor">#</a></h2>
<p>Templates become first-class citizens via a new top-level <code>templates/</code>
directory. Would <code>tpl</code> make more sense compared to the other short 3-letter
directory names?</p>
<p>Why not <code>views</code>? <code>views</code> was the original name I chose very early on because it
was shorter than <code>templates</code>. It was a mistake as <code>View</code> is a concept by itself.
Fixed, finally.</p>
<p>Having templates at the root level also makes working with web designers
easier. And this directory is only created when you install Twig.</p>
<p>Moving templates allows to reserve <code>src/</code> for PHP classes only, no more
resources. Another consequence of being bundle-less.</p>
<h2 id="configuration-under-config">Configuration under <code>config/</code><a href="#configuration-under-config" class="anchor">#</a></h2>
<p>The new <code>config/</code> directory is the equivalent of the current <code>app/config/</code>
directory. But with a very different layout. <code>parameters.yml</code> and
<code>parameters.yml.dist</code> are gone.</p>
<p>The main entry point for the container is an empty <code>container.yaml</code> that you
can use to define your own services and parameters. Configuration for bundles
that you install via Composer are stored as <strong>individual</strong> files. One file per
bundle and per environment. The same goes for the routing configuration. That's
a soft requirement for auto-configuration, but allows for a better file
organization.</p>
<p>Configuration files can be written in PHP, XML, or YAML as before. The only
difference being the usage of the standard <code>.yaml</code> extension instead of the
current <code>.yml</code> one.</p>
<p>One major change is the introduction of a <code>bundles.php</code> file where installed
bundles are referenced.</p>
<p>One file per bundle and <code>bundles.php</code> are the two core concepts that enables
Symfony to automatically manage your bundles and their configurations.</p>
<h2 id="source-code-under-src">Source Code under <code>src/</code><a href="#source-code-under-src" class="anchor">#</a></h2>
<p>The <code>Kernel</code> class has been moved to <code>src/</code>, where it belongs. The content is
very different from the one in Symfony 2. First, it uses the <code>MicroKernelTrait</code>
trait. Then, it implements the logic to load the bundles from <code>bundles.php</code> and
to read the various bundle configuration files. The logic works as of Symfony
3.3. For instance, the code that loads the container configuration files reads
as follow:</p>
<pre><code class="language-php">protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader)
{
    $confDir = dirname(__DIR__).'/config';
    $loader->import($confDir.'/packages/*'.self::CONFIG_EXTS, 'glob');
    if (is_dir($confDir.'/packages/'.$this->getEnvironment())) {
        $loader->import($confDir.'/packages/'.$this->getEnvironment().'/**/*'.self::CONFIG_EXTS, 'glob');
    }
    $loader->import($confDir.'/container'.self::CONFIG_EXTS, 'glob');
}</code></pre>
<h2 id="temporary-files-under-var">Temporary files under <code>var/</code><a href="#temporary-files-under-var" class="anchor">#</a></h2>
<p><code>var/</code> is very similar to Symfony 3, with some minor tweaks in the best
practices.</p>
<p><code>var/cache/</code> should now only be used to store long term cached contents like
compiled container files, compiled translations, or Doctrine proxies. No
temporary files. Basically, anything stored under <code>var/cache</code> should have a
warmup class able to generate the cache files. Files that should never be
updated after deployment to allow for read-only filesystems.</p>
<p>What about temporary files then? Use another directory like <code>var/tmp/</code>. Or just
the standard Unix <code>/tmp</code> directory.</p>
<p>If you follow this best practice, we will be able to guarantee a read-only
<code>/var/cache</code> directory at some point. Having read-only directories is a
requirement of some hosting platforms like Heroku or SensioCloud and helps
scale an application. Probably not for Symfony 4.0 though.</p>
<h2 id="web-files-under-public">Web files under <code>public/</code><a href="#web-files-under-public" class="anchor">#</a></h2>
<p>I have already mentioned the single web front controller under <code>public/</code>.
Almost all the other files were removed. No <code>config.php</code>. No <code>.htaccess</code>. No
<code>favicon.ico</code> or <code>apple-touch-icon.png</code>. Not even <code>robots.txt</code>. Not all
projects need those files. If you want skeletons for those files, I got you
covered of course.</p>
<h2 id="everything-is-optional">Everything is optional<a href="#everything-is-optional" class="anchor">#</a></h2>
<p>One difference with Symfony 3 is that all first-level directories are optional.
Don't use templates for you API? No need to create a <code>templates/</code> directory.
Directories are created on-demand anyway.</p>
<p>When using Composer to add a new bundle, Symfony 4 levers this new directory
structure to automatically register the bundle in <code>bundles.php</code>, copy some
sensible configuration under <code>config/</code>, and much more. What else you ask? Great
topic for the next post.</p>]]></content>
    </entry></feed>
