Symfony 4: A quick Demo
Fabien Potencier
May 2, 2017
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.
Creating a new Project
The first step is to create a project. Currently, this needs to be done via
composer create-project. We might release a tool to bootstrap a project
faster.
Let’s go:
composer create-project "symfony/skeleton:^3.3" demo
cd demo
3.3 is the only currently available version and uses the yet-to-be-released
Symfony 3.3. Versions like , 4.0, lts, or latest will be available
later on (but not before the release of Symfony 4.0
of course).
The command downloads the Symfony
skeleton which consists of just one
composer.json file.
Then, it extracts the file into the demo directory and automatically runs
composer install. symfony/flex 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 recipe on the
Symfony Flex server, and executes it. You can see Symfony Flex in action via
the logs it adds to the Composer output.

When finished, you should see a “What’s next?” section that explains the
possible next steps, like running make serve to start the PHP built-in web
server. Before going further, go to the project’s directory: cd demo.

serve is one of the tasks added to the local Makefile, as described in the
symfony/framework-bundle
recipe.
Note that some commands were automatically installed and run at the end of the process:

Again, those scripts were added to the project’s composer.json file as
defined by the symfony/framework-bundle recipe. The second script did not run
because the console tool (available via symfony/console) is not installed by
default (we will see how to “fix” this issue later on).
Now is a good time to initialize Git:
git init
git add .
git commit -m "initial set of files"
Using git add . works well as Symfony took care of creating a “good”
.gitignore file.
Remember that the skeleton only has one file, composer.json. Check the
demo/ directory now; some more files have been created. Those files were
added by Symfony Flex based on the installed packages, as described in recipes.
Let’s examine the directory structure now. Most files has been added because of
the symfony/framework-bundle dependency.
The .env file defines the APP_ENV and APP_DEBUG environment variables:
###> symfony/framework-bundle ###
APP_ENV=dev
APP_DEBUG=1
APP_SECRET=ODtvoHW6pn3bE2rHgTa2MjkjwefzlsJH
###< symfony/framework-bundle ###
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 .gitignore for a similar example.
If you’re curious, check public/index.php, the new web front controller.
The most interesting files are under config/. The main entry points are the
empty container.yaml and routing.yaml files; this is where you can add
services, parameters, and routes for your project. A default configuration has
been installed as well for symfony/framework-bundle under config/packages/.
Feel free to tweak installed configuration files or add more for your own needs.
Last, but not least, FrameworkBundle is now registered in bundles.php:
return [
'Symfony\Bundle\FrameworkBundle\FrameworkBundle' => ['all' => true],
];
Even if a bundle does not have a recipe, Symfony detects Composer packages with
the symfony-bundle type and automatically enable them for all environments.
This avoids the creation of recipes when registration is just a matter of
enabling the bundle.
The src/ directory is where you can store your PHP classes. Under the App\
namespace as registered in composer.json. Note that this is where
Kernel.php was also installed as App\Kernel.
Now, it is time to install some new dependencies via Composer. Let’s start by adding a more powerful web server for your project:
composer req webserver
And install Symfony console support via:
composer req cli
Note: req is a shortcut for require (the Composer CLI supports any
shortcut that is not ambiguous; use rem to remove a Package).
webserver is an alias for symfony/web-server-bundle, and cli is an
alias for symfony/console. That works because Symfony Flex knows how to
convert those aliases into full package names: cli is equivalent to
console, which is equivalent to symfony/console. The symfony/ prefix is
always optional. Try composer req workflow or composer req ldap.
web-server-bundle is too cumbersome, so use webserver or just server.
For Symfony dependencies, Symfony Flex also recognizes a few more versions than
the usual Composer ones, mainly next, previous, lts, and stable (they
don’t all work yet though).
composer req cli:next
After executing composer req cli, notice how the assets:install command
automatically ran. The bin/console file has also been added to your project.

Aliases work when removing dependency as well:
composer rem cli
… which also removes the bin/console binary (for fun, try this: composer rem framework-bundle).
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.
First, let’s install EasyAdminBundle:
composer req admin
Besides installing the admin generator bundle, it also installs all its
transitive dependencies and auto-configures them all: TwigBundle,
SecurityBundle, FrameworkExtraBundle, and DoctrineBundle.
admin is a “generic” word. This is why I wrote about Symfony Flex recipes
being opinionated. There can only be one package aliased to admin. orm is
another generic word that is currently aliased to the Doctrine ORM.
Run the PHP built-in web-server via make serve or bin/console server:start
and go to http://localhost:8000/admin/. You should get an error as no
Doctrine entities exist yet. Let’s create one in src/Entity/Product.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;
}
Tweak the database configuration in .env:
###> doctrine/doctrine-bundle ###
DB_URL=mysql://root@127.0.0.1:3306/symfony?charset=utf8mb4
###< doctrine/doctrine-bundle ###
Run the following commands to initialize the database:
./bin/console doctrine:database:create
./bin/console doctrine:schema:update --force
Finally, add the Product entity to the list of entities managed by the admin
generator (config/packages/easy_admin.yaml):
easy_admin:
entities:
- App\Entity\Product
Try http://localhost:8000/admin/ again. If everything worked well, you should
be able to manage products.

Instead of installing an admin generator, have a look at this small screencast
where I’m using the api alias to bootstrap an API project quickly and easily:
Here are some nice aliases you can try:
sec-checkerto install the SensioLabs Security Checker;req-checkerto install the Symfony requirements checks;logto install MonologBundle and all its dependencies;templatefor Twig;mailerfor Swiftmailer;profilerfor the profiler;- … you get the point :)
As symfony/symfony 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 composer.json that references a set of related packages. As an
example, I have created a debug-pack
pack that can be installed via
composer req debug-pack. Have a look at the ORM
pack or the API
pack. Imagine a web-pack that
references nothing in composer.json but is associated with a recipe that
installs a set of default files under public/ like favicons, a robots.txt,
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.
Symfony Flex enables distribution composition instead of inheritance. The new way is easier, more flexible, and more powerful at the same time.
The first version of the Symfony Flex server is quite simple, but over time, more features will be implemented.
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.
Remember that the recipes repositories at https://github.com/symfony/recipes and https://github.com/symfony/recipes-contrib are also public now. Feel free to look around. And keep in mind that what you see is experimental. Current choices might change.