From baf4b9b37f6506327a78ca0bb3a15250ce2c352e Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 25 Oct 2014 19:08:50 +0200 Subject: [PATCH 1/4] Revamped the Quick Start tutorial --- quick_tour/the_architecture.rst | 150 +++++------ quick_tour/the_big_picture.rst | 430 ++++++++++++++------------------ quick_tour/the_controller.rst | 306 +++++++++++++++++------ quick_tour/the_view.rst | 186 +++++++------- 4 files changed, 562 insertions(+), 510 deletions(-) diff --git a/quick_tour/the_architecture.rst b/quick_tour/the_architecture.rst index 927f4512e60..9667fee3d70 100644 --- a/quick_tour/the_architecture.rst +++ b/quick_tour/the_architecture.rst @@ -13,17 +13,17 @@ Understanding the Directory Structure The directory structure of a Symfony :term:`application` is rather flexible, but the recommended structure is as follows: -* ``app/``: the application configuration; -* ``src/``: the project's PHP code; +* ``app/``: the application configuration and templates; +* ``src/``: the project's PHP code; * ``vendor/``: the third-party dependencies; -* ``web/``: the web root directory. +* ``web/``: the web root directory. The ``web/`` Directory ~~~~~~~~~~~~~~~~~~~~~~ The web root directory is the home of all public and static files like images, stylesheets, and JavaScript files. It is also where each :term:`front controller` -lives:: +lives, such as the production controller shown here:: // web/app.php require_once __DIR__.'/../app/bootstrap.php.cache'; @@ -33,7 +33,9 @@ lives:: $kernel = new AppKernel('prod', false); $kernel->loadClassCache(); - $kernel->handle(Request::createFromGlobals())->send(); + $request = Request::createFromGlobals(); + $response = $kernel->handle($request); + $response->send(); The controller first bootstraps the application using a kernel class (``AppKernel`` in this case). Then, it creates the ``Request`` object using the PHP's global @@ -51,8 +53,7 @@ configuration and as such, it is stored in the ``app/`` directory. This class must implement two methods: * ``registerBundles()`` must return an array of all bundles needed to run the - application; - + application, as explained in the next section; * ``registerContainerConfiguration()`` loads the application configuration (more on this later). @@ -73,12 +74,21 @@ A bundle is kind of like a plugin in other software. So why is it called a Symfony, from the core framework features to the code you write for your application. +All the code you write for your application is organized in bundles. In Symfony +speak, a bundle is a structured set of files (PHP files, stylesheets, JavaScripts, +images, ...) that implements a single feature (a blog, a forum, ...) and which +can be easily shared with other developers. + Bundles are first-class citizens in Symfony. This gives you the flexibility to use pre-built features packaged in third-party bundles or to distribute your own bundles. It makes it easy to pick and choose which features to enable in your application and optimize them the way you want. And at the end of the day, your application code is just as *important* as the core framework itself. +Symfony already includes an ``AppBundle`` that you may use to start developing +your application. Then, if you need to split the application into reusable +components, you can create your own bundles. + Registering a Bundle ~~~~~~~~~~~~~~~~~~~~ @@ -98,10 +108,10 @@ a single ``Bundle`` class that describes it:: new Symfony\Bundle\DoctrineBundle\DoctrineBundle(), new Symfony\Bundle\AsseticBundle\AsseticBundle(), new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(), + new AppBundle\AppBundle(); ); if (in_array($this->getEnvironment(), array('dev', 'test'))) { - $bundles[] = new Acme\DemoBundle\AcmeDemoBundle(); $bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle(); $bundles[] = new Sensio\Bundle\DistributionBundle\SensioDistributionBundle(); $bundles[] = new Sensio\Bundle\GeneratorBundle\SensioGeneratorBundle(); @@ -110,16 +120,15 @@ a single ``Bundle`` class that describes it:: return $bundles; } -In addition to the AcmeDemoBundle that was already talked about, notice -that the kernel also enables other bundles such as the FrameworkBundle, -DoctrineBundle, SwiftmailerBundle and AsseticBundle bundle. They are all part -of the core framework. +In addition to the AppBundle that was already talked about, notice that the +kernel also enables other bundles such as the FrameworkBundle, DoctrineBundle, +SwiftmailerBundle and AsseticBundle bundle. They are all part of the core framework. Configuring a Bundle ~~~~~~~~~~~~~~~~~~~~ Each bundle can be customized via configuration files written in YAML, XML, or -PHP. Have a look at the default Symfony configuration: +PHP. Have a look at this sample of the default Symfony configuration: .. code-block:: yaml @@ -127,6 +136,7 @@ PHP. Have a look at the default Symfony configuration: imports: - { resource: parameters.yml } - { resource: security.yml } + - { resource: services.yml } framework: #esi: ~ @@ -138,7 +148,7 @@ PHP. Have a look at the default Symfony configuration: form: true csrf_protection: true validation: { enable_annotations: true } - templating: { engines: ['twig'] } #assets_version: SomeVersionScheme + templating: { engines: ['twig'] } default_locale: "%locale%" trusted_proxies: ~ session: ~ @@ -148,34 +158,6 @@ PHP. Have a look at the default Symfony configuration: debug: "%kernel.debug%" strict_variables: "%kernel.debug%" - # Assetic Configuration - assetic: - debug: "%kernel.debug%" - use_controller: false - bundles: [ ] - #java: /usr/bin/java - filters: - cssrewrite: ~ - #closure: - # jar: "%kernel.root_dir%/Resources/java/compiler.jar" - #yui_css: - # jar: "%kernel.root_dir%/Resources/java/yuicompressor-2.4.7.jar" - - # Doctrine Configuration - doctrine: - dbal: - driver: "%database_driver%" - host: "%database_host%" - port: "%database_port%" - dbname: "%database_name%" - user: "%database_user%" - password: "%database_password%" - charset: UTF8 - - orm: - auto_generate_proxy_classes: "%kernel.debug%" - auto_mapping: true - # Swift Mailer Configuration swiftmailer: transport: "%mailer_transport%" @@ -184,9 +166,11 @@ PHP. Have a look at the default Symfony configuration: password: "%mailer_password%" spool: { type: memory } -Each first level entry like ``framework``, ``twig`` or ``doctrine`` defines the -configuration for a specific bundle. For example, ``framework`` configures the -FrameworkBundle while ``swiftmailer`` configures the SwiftmailerBundle. + # ... + +Each first level entry like ``framework``, ``twig`` or ``swiftmailer`` defines +the configuration for a specific bundle. For example, ``framework`` configures +the FrameworkBundle while ``swiftmailer`` configures the SwiftmailerBundle. Each :term:`environment` can override the default configuration by providing a specific configuration file. For example, the ``dev`` environment loads the @@ -207,18 +191,7 @@ and then modifies it to add some debugging tools: toolbar: true intercept_redirects: false - monolog: - handlers: - main: - type: stream - path: "%kernel.logs_dir%/%kernel.environment%.log" - level: debug - firephp: - type: firephp - level: info - - assetic: - use_controller: true + # ... Extending a Bundle ~~~~~~~~~~~~~~~~~~ @@ -226,8 +199,6 @@ Extending a Bundle In addition to being a nice way to organize and configure your code, a bundle can extend another bundle. Bundle inheritance allows you to override any existing bundle in order to customize its controllers, templates, or any of its files. -This is where the logical names (e.g. ``@AcmeDemoBundle/Controller/SecuredController.php``) -come in handy: they abstract where the resource is actually stored. Logical File Names .................. @@ -235,36 +206,27 @@ Logical File Names When you want to reference a file from a bundle, use this notation: ``@BUNDLE_NAME/path/to/file``; Symfony will resolve ``@BUNDLE_NAME`` to the real path to the bundle. For instance, the logical path -``@AcmeDemoBundle/Controller/DemoController.php`` would be converted to -``src/Acme/DemoBundle/Controller/DemoController.php``, because Symfony knows -the location of the AcmeDemoBundle. +``@AppBundle/Controller/DefaultController.php`` would be converted to +``src/AppBundle/Controller/DefaultController.php``, because Symfony knows +the location of the AppBundle. Logical Controller Names ........................ -For controllers, you need to reference method names using the format +For controllers, you need to reference action using the format ``BUNDLE_NAME:CONTROLLER_NAME:ACTION_NAME``. For instance, -``AcmeDemoBundle:Welcome:index`` maps to the ``indexAction`` method from the -``Acme\DemoBundle\Controller\WelcomeController`` class. - -Logical Template Names -...................... - -For templates, the logical name ``AcmeDemoBundle:Welcome:index.html.twig`` is -converted to the file path ``src/Acme/DemoBundle/Resources/views/Welcome/index.html.twig``. -Templates become even more interesting when you realize they don't need to be -stored on the filesystem. You can easily store them in a database table for -instance. +``AppBundle:Default:index`` maps to the ``indexAction`` method from the +``AppBundle\Controller\DefaultController`` class. Extending Bundles ................. -If you follow these conventions, then you can use :doc:`bundle inheritance` -to "override" files, controllers or templates. For example, you can create -a bundle - AcmeNewBundle - and specify that it overrides AcmeDemoBundle. -When Symfony loads the ``AcmeDemoBundle:Welcome:index`` controller, it will -first look for the ``WelcomeController`` class in AcmeNewBundle and, if -it doesn't exist, then look inside AcmeDemoBundle. This means that one bundle +If you follow these conventions, then you can use :doc:`bundle inheritance ` +to override files, controllers or templates. For example, you can create +a bundle - NewBundle - and specify that it overrides AppBundle. +When Symfony loads the ``AppBundle:Default:index`` controller, it will +first look for the ``DefaultController`` class in NewBundle and, if +it doesn't exist, then look inside AppBundle. This means that one bundle can override almost any part of another bundle! Do you understand now why Symfony is so flexible? Share your bundles between @@ -276,22 +238,28 @@ Using Vendors ------------- Odds are that your application will depend on third-party libraries. Those -should be stored in the ``vendor/`` directory. This directory already contains -the Symfony libraries, the SwiftMailer library, the Doctrine ORM, the Twig -templating system, and some other third party libraries and bundles. +should be stored in the ``vendor/`` directory and managed by Composer. +This directory already contains the Symfony libraries, the SwiftMailer library, +the Doctrine ORM, the Twig templating system, and some other third party +libraries and bundles. Understanding the Cache and Logs -------------------------------- -Symfony is probably one of the fastest full-stack frameworks around. But how -can it be so fast if it parses and interprets tens of YAML and XML files for -each request? The speed is partly due to its cache system. The application +Symfony applications can contain tens of configuration files defined in several +formats (YAML, XML, PHP, etc.) Instead of parsing and combining all those files +for each request, Symfony uses its own cache system. In fact, the application configuration is only parsed for the very first request and then compiled down -to plain PHP code stored in the ``app/cache/`` directory. In the development -environment, Symfony is smart enough to flush the cache when you change a -file. But in the production environment, to speed things up, it is your -responsibility to clear the cache when you update your code or change its -configuration. +to plain PHP code stored in the ``app/cache/`` directory. + +In the development environment, Symfony is smart enough to update the cache when +you change a file. But in the production environment, to speed things up, it is +your responsibility to clear the cache when you update your code or change its +configuration. Execute this command to clear the cache in the ``prod`` environment: + +.. code-block:: bash + + $ php app/console cache:clear --env=prod When developing a web application, things can go wrong in many ways. The log files in the ``app/logs/`` directory tell you everything about the requests diff --git a/quick_tour/the_big_picture.rst b/quick_tour/the_big_picture.rst index 212f406e62c..c1a1493e62f 100644 --- a/quick_tour/the_big_picture.rst +++ b/quick_tour/the_big_picture.rst @@ -1,81 +1,95 @@ The Big Picture =============== -Start using Symfony in 10 minutes! This chapter will walk you through some of -the most important concepts behind Symfony and explain how you can get started -quickly by showing you a simple project in action. +Start using Symfony in 10 minutes! This chapter will walk you through the most +important concepts behind Symfony and explain how you can get started quickly +by showing you a simple project in action. If you've used a web framework before, you should feel right at home with Symfony. If not, welcome to a whole new way of developing web applications. +The only technical requisite to follow this tutorial is to have **PHP 5.4 or higher +installed on your computer**. If you use a packaged PHP solution such as WAMP, +XAMP or MAMP, check out that they are using PHP 5.4 or a more recent version. +You can also execute the following command in your terminal or command console +to display the installed PHP version: + +.. code-block:: bash + + php --version + .. _installing-symfony2: Installing Symfony ------------------ -First, check that the PHP version installed on your computer meets the Symfony -requirements: 5.3.3 or higher. Then, open a console and execute the following -command to install the latest version of Symfony in the ``myproject/`` -directory: - -.. code-block:: bash +In the past, Symfony had to be installed manually for each new project. In order +to simplify this set up, a new **Symfony Installer** was introduced recently. +This means that the very first time you use Symfony on a computer, you have to +install the Symfony Installer. - $ composer create-project symfony/framework-standard-edition myproject/ '~2.3' +On **Linux** and **Mac OS X** systems, execute the following console commands: -.. tip:: +.. code-block:: bash - Add the ``-vvv`` flag to see everything that Composer is doing - this is - especially useful on a slow connection where it may seem that nothing is - happening. + $ curl -sS https://symfony.com/installer | php + $ sudo mv symfony.phar /usr/local/bin/symfony .. note:: - `Composer`_ is the package manager used by modern PHP applications and the - only recommended way to install Symfony. To install Composer on your - Linux or Mac system, execute the following commands: + If your system doesn't have cURL installed, execute instead the following + command: .. code-block:: bash - $ curl -sS https://getcomposer.org/installer | php - $ sudo mv composer.phar /usr/local/bin/composer - - To install Composer on a Windows system, download the `executable installer`_. + $ php -r "readfile('https://symfony.com/installer');" | php -Beware that the first time you install Symfony, it may take a few minutes to -download all its components. At the end of the installation process, the -installer will ask you to provide some configuration options for the Symfony -project. For this first project you can safely ignore this configuration by -pressing the ```` key repeatedly. +After installing the Symfony installer, you'll have to open a new console window +to be able to execute the new ``symfony`` command: -.. _running-symfony2: +.. code-block:: bash -Running Symfony ---------------- + $ symfony -Before running Symfony for the first time, execute the following command to -make sure that your system meets all the technical requirements: +On **Windows** systems, download the ``symfony.phar`` file from ........... and +save it into the directory where you create the Symfony projects. Then you can +execute the Symfony installer right away with this command: .. code-block:: bash - $ cd myproject/ - $ php app/check.php + c:\> php symfony.phar + +Creating Your First Symfony Project +----------------------------------- -Fix any error reported by the command and then use the PHP built-in web server -to run Symfony: +Once the Symfony Installer is set up, use the ``new`` command to create new +Symfony projects. Let's create a new project called ``myproject``: .. code-block:: bash - $ php app/console server:run + # Linux and Mac OS X + $ symfony new myproject + + # Windows + c:\> php symfony.phar new myproject + +This command downloads the latest Symfony stable version and creates an empty +project in the ``myproject/`` directory so you can start developing your +application right away. + +.. _running-symfony2: + +Running Symfony +--------------- -.. seealso:: +This tutorial leverages the internal web server provided by PHP to run Symfony +applications. Therefore, running a Symfony application is a matter of browsing +the project directory and executing this command: - Read more about the internal server :doc:`in the cookbook `. +.. code-block:: bash -If you get the error `There are no commands defined in the "server" namespace.`, -then you are probably using PHP 5.3. That's ok! But the built-in web server is -only available for PHP 5.4.0 or higher. If you have an older version of PHP or -if you prefer a traditional web server such as Apache or Nginx, read the -:doc:`/cookbook/configuration/web_server_configuration` article. + $ cd myproject/ + $ php app/console server:start Open your browser and access the ``http://localhost:8000`` URL to see the Welcome page of Symfony: @@ -84,235 +98,169 @@ Welcome page of Symfony: :align: center :alt: Symfony Welcome Page -Understanding the Fundamentals ------------------------------- - -One of the main goals of a framework is to keep your code organized and to allow -your application to evolve easily over time by avoiding the mixing of database -calls, HTML tags and business logic in the same script. To achieve this goal -with Symfony, you'll first need to learn a few fundamental concepts and terms. - -Symfony comes with some sample code that you can use to learn more about its -main concepts. Go to the following URL to be greeted by Symfony (replace -*Fabien* with your first name): - -.. code-block:: text - - http://localhost:8000/app_dev.php/demo/hello/Fabien - -.. image:: /images/quick_tour/hello_fabien.png - :align: center +Congratulations! Your first Symfony project is up and running! .. note:: - Instead of the greeting page, you may see a blank page or an error page. + Instead of the welcome page, you may see a blank page or an error page. This is caused by a directory permission misconfiguration. There are several possible solutions depending on your operating system. All of them are explained in the :ref:`Setting up Permissions ` section of the official book. -What's going on here? Have a look at each part of the URL: - -* ``app_dev.php``: This is a :term:`front controller`. It is the unique entry - point of the application and it responds to all user requests; - -* ``/demo/hello/Fabien``: This is the *virtual path* to the resource the user - wants to access. +When you are finished working on your Symfony application, you can stop the +server with the ``server:stop`` command: -Your responsibility as a developer is to write the code that maps the user's -*request* (``/demo/hello/Fabien``) to the *resource* associated with it -(the ``Hello Fabien!`` HTML page). - -Routing -~~~~~~~ - -Symfony routes the request to the code that handles it by matching the -requested URL (i.e. the virtual path) against some configured paths. The demo -paths are defined in the ``app/config/routing_dev.yml`` configuration file: - -.. code-block:: yaml - - # app/config/routing_dev.yml - # ... - - # AcmeDemoBundle routes (to be removed) - _acme_demo: - resource: "@AcmeDemoBundle/Resources/config/routing.yml" - -This imports a ``routing.yml`` file that lives inside the AcmeDemoBundle: - -.. code-block:: yaml - - # src/Acme/DemoBundle/Resources/config/routing.yml - _welcome: - path: / - defaults: { _controller: AcmeDemoBundle:Welcome:index } - - _demo: - resource: "@AcmeDemoBundle/Controller/DemoController.php" - type: annotation - prefix: /demo - - # ... +.. code-block:: bash -The first three lines (after the comment) define the code that is executed -when the user requests the "``/``" resource (i.e. the welcome page you saw -earlier). When requested, the ``AcmeDemoBundle:Welcome:index`` controller -will be executed. In the next section, you'll learn exactly what that means. + $ php app/console server:stop .. tip:: - In addition to YAML files, routes can be configured in XML or PHP files - and can even be embedded in PHP annotations. This flexibility is one of the - main features of Symfony, a framework that never imposes a particular - configuration format on you. + If you prefer a traditional web server such as Apache or Nginx, read the + :doc:`/cookbook/configuration/web_server_configuration` article. + +Understanding the Fundamentals +------------------------------ -Controllers -~~~~~~~~~~~ +One of the main goals of a framework is to keep your code organized and to allow +your application to evolve easily over time by avoiding the mixing of database +calls, HTML tags and other PHP code in the same script. To achieve this goal +with Symfony, you'll first need to learn a few fundamental concepts. -A controller is a PHP function or method that handles incoming *requests* and -returns *responses* (often HTML code). Instead of using the PHP global variables -and functions (like ``$_GET`` or ``header()``) to manage these HTTP messages, -Symfony uses objects: :ref:`Request ` -and :ref:`Response `. The simplest possible -controller might create the response by hand, based on the request:: +When developing a Symfony application, your responsibility as a developer is to +write the code that maps the user's *request* (e.g. ``http://localhost:8000/``) +to the *resource* associated with it (the ``Welcome to Symfony!`` HTML page). - use Symfony\Component\HttpFoundation\Response; +The code to execute is defined in **actions** and **controllers**. The mapping +between user's requests and that code is defined via the **routing** configuration. +And the contents displayed in the browser are usually rendered using **templates**. - $name = $request->get('name'); +When you browsed ``http://localhost:8000/`` earlier, Symfony executed the +controller defined in the ``src/AppBundle/Controller/DefaultController.php`` +file and rendered the ``app/Resources/views/default/index.html.twig`` template. +In the following sections you'll learn in detail the inner workings of Symfony +controllers, routes and templates. - return new Response('Hello '.$name); +Actions and Controllers +~~~~~~~~~~~~~~~~~~~~~~~ -Symfony chooses the controller based on the ``_controller`` value from the -routing configuration: ``AcmeDemoBundle:Welcome:index``. This string is the -controller *logical name*, and it references the ``indexAction`` method from -the ``Acme\DemoBundle\Controller\WelcomeController`` class:: +Open the ``src/AppBundle/Controller/DefaultController.php`` file and you'll see +the following code (for now, don't look at the ``@Route`` configuration because +that will be explained in the next section):: - // src/Acme/DemoBundle/Controller/WelcomeController.php - namespace Acme\DemoBundle\Controller; + namespace AppBundle\Controller; + use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Symfony\Bundle\FrameworkBundle\Controller\Controller; - class WelcomeController extends Controller + class DefaultController extends Controller { + /** + * @Route("/", name="homepage") + */ public function indexAction() { - return $this->render('AcmeDemoBundle:Welcome:index.html.twig'); + return $this->render('default/index.html.twig'); } } -.. tip:: - - You could have used the full class and method name - - ``Acme\DemoBundle\Controller\WelcomeController::indexAction`` - for the - ``_controller`` value. But using the logical name is shorter and allows - for more flexibility. +In Symfony applications, **controllers** are PHP classes whose names are suffixed +with the ``Controller`` word. In this example, the controller is called ``Default`` +and the PHP class is called ``DefaultController``. -The ``WelcomeController`` class extends the built-in ``Controller`` class, -which provides useful shortcut methods, like the -:ref:`render()` method that loads and renders -a template (``AcmeDemoBundle:Welcome:index.html.twig``). The returned value -is a ``Response`` object populated with the rendered content. So, if the need -arises, the ``Response`` can be tweaked before it is sent to the browser:: +The methods defined in a controller are called **actions**, they are usually +associated with one URL of the application and their names are suffixed with +``Action``. In this example, the ``Default`` controller has only one action +called ``index`` and defined in the ``indexAction`` method. - public function indexAction() - { - $response = $this->render('AcmeDemoBundle:Welcome:index.txt.twig'); - $response->headers->set('Content-Type', 'text/plain'); - - return $response; - } +Actions are usually very short - around 10-15 lines of code - because they just +call other parts of the application to get or generate the needed information and +then they render a template to show the results to the user. -No matter how you do it, the end goal of your controller is always to return -the ``Response`` object that should be delivered back to the user. This ``Response`` -object can be populated with HTML code, represent a client redirect, or even -return the contents of a JPG image with a ``Content-Type`` header of ``image/jpg``. +In this example, the ``index`` action is practically empty because it doesn't +need to call any other method. The action just renders a template with the +*Welcome to Symfony!* content. -The template name, ``AcmeDemoBundle:Welcome:index.html.twig``, is the template -*logical name* and it references the ``Resources/views/Welcome/index.html.twig`` -file inside the AcmeDemoBundle (located at ``src/Acme/DemoBundle``). -The `Bundles`_ section below will explain why this is useful. +Routing +~~~~~~~ -Now, take a look at the routing configuration again and find the ``_demo`` -key: +Symfony routes each request to the action that handles it by matching the +requested URL against the paths configured by the application. Open again the +``src/AppBundle/Controller/DefaultController.php`` file and take a look at the +three lines of code above the ``indexAction`` method: -.. code-block:: yaml +.. code-block:: php - # src/Acme/DemoBundle/Resources/config/routing.yml - # ... - _demo: - resource: "@AcmeDemoBundle/Controller/DemoController.php" - type: annotation - prefix: /demo + // src/AppBundle/Controller/DefaultController.php + namespace AppBundle\Controller; -The *logical name* of the file containing the ``_demo`` routes is -``@AcmeDemoBundle/Controller/DemoController.php`` and refers -to the ``src/Acme/DemoBundle/Controller/DemoController.php`` file. In this -file, routes are defined as annotations on action methods:: - - // src/Acme/DemoBundle/Controller/DemoController.php use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; - use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; + use Symfony\Bundle\FrameworkBundle\Controller\Controller; - class DemoController extends Controller + class DefaultController extends Controller { /** - * @Route("/hello/{name}", name="_demo_hello") - * @Template() + * @Route("/", name="homepage") */ - public function helloAction($name) + public function indexAction() { - return array('name' => $name); + return $this->render('default/index.html.twig'); } - - // ... } -The ``@Route()`` annotation creates a new route matching the ``/hello/{name}`` -path to the ``helloAction()`` method. Any string enclosed in curly brackets, -like ``{name}``, is considered a variable that can be directly retrieved as a -method argument with the same name. +These three lines define the routing configuration via the ``@Route()`` annotation. +A **PHP annotation** is a convenient way to configure a method without having to +write regular PHP code. Beware that annotation blocks start with ``/**``, whereas +regular PHP comments start with ``/*``. + +The first value of ``@Route()`` defines the path that will trigger the execution +of the action. This path is configured via a relative URL, so you don't have to +add the host of your application (e.g. ```http://example.com``). In this case, +the value ``/`` refers to the application homepage. The second value of ``@Route()`` +(e.g. ``name="homepage"``) is optional and sets the name of this route. For now +this name is not needed, but later it'll be useful for linking pages. + +Considering all this, the ``@Route("/", name="homepage")`` annotation creates a +new route called ``homepage`` which makes Symfony execute the ``index`` action +of the ``Default`` controller when the users browses the ``/`` URL of the application. + +.. tip:: -If you take a closer look at the controller code, you can see that instead of -rendering a template and returning a ``Response`` object like before, it -just returns an array of parameters. The ``@Template()`` annotation tells -Symfony to render the template for you, passing to it each variable of the -returned array. The name of the template that's rendered follows the name -of the controller. So, in this example, the ``AcmeDemoBundle:Demo:hello.html.twig`` -template is rendered (located at ``src/Acme/DemoBundle/Resources/views/Demo/hello.html.twig``). + In addition to PHP annotations, routes can be configured in YAML, XML or + PHP files. This flexibility is one of the main features of Symfony, a + framework that never imposes a particular configuration format on you. Templates ~~~~~~~~~ -The controller renders the ``src/Acme/DemoBundle/Resources/views/Demo/hello.html.twig`` -template (or ``AcmeDemoBundle:Demo:hello.html.twig`` if you use the logical name): +The only content of the ``index`` action is this PHP instruction: -.. code-block:: jinja +.. code-block:: php - {# src/Acme/DemoBundle/Resources/views/Demo/hello.html.twig #} - {% extends "AcmeDemoBundle::layout.html.twig" %} + return $this->render('default/index.html.twig'); - {% block title "Hello " ~ name %} +The ``$this->render()`` method is a convenient shortcut to render a template. +Symfony provides some useful shortcuts to any controller extending from the +``Controller`` class. - {% block content %} -

Hello {{ name }}!

- {% endblock %} +By default, application templates are stored in the ``app/Resources/views/`` +directory. Therefore, the ``default/index.html.twig`` template corresponds to the +``app/Resources/views/default/index.html.twig``. Open that file and you'll see +the following code: -By default, Symfony uses `Twig`_ as its template engine but you can also use -traditional PHP templates if you choose. The -:doc:`second part of this tutorial` will introduce how -templates work in Symfony. +.. code-block:: html+jinja -Bundles -~~~~~~~ + {# app/Resources/views/default/index.html.twig #} + {% extends 'base.html.twig' %} + + {% block body %} +

Welcome to Symfony!

+ {% endblock %} -You might have wondered why the :term:`Bundle` word is used in many names you -have seen so far. All the code you write for your application is organized in -bundles. In Symfony speak, a bundle is a structured set of files (PHP files, -stylesheets, JavaScripts, images, ...) that implements a single feature (a -blog, a forum, ...) and which can be easily shared with other developers. As -of now, you have manipulated one bundle, AcmeDemoBundle. You will learn -more about bundles in the :doc:`last part of this tutorial`. +This template is created with `Twig`_, a new template engine created for modern +PHP applications. The :doc:`second part of this tutorial` +will introduce how templates work in Symfony. .. _quick-tour-big-picture-environments: @@ -334,9 +282,13 @@ the request, the query parameters, security details, and database queries: .. image:: /images/quick_tour/profiler.png :align: center -Of course, it would be unwise to have this tool enabled when you deploy your -application, so by default, the profiler is not enabled in the ``prod`` -environment. +This tool provides so much internal information about your application that you +may be worried about your visitors accessing sensible information. Symfony is +aware of this issue and for that reason, it won't display this bar when your +application is running in the production server. + +How does Symfony knows when is your application running locally or in a production +server? Keep reading to discover the concept of **execution environments**. .. _quick-tour-big-picture-environments-intro: @@ -348,6 +300,22 @@ your application. Symfony defines two environments by default: ``dev`` (suited for when developing the application locally) and ``prod`` (optimized for when executing the application on production). +When you visit the ``http://localhost:8000`` URL in your browser, you're executing +your Symfony application in the ``dev`` environment. To visit your application +in the ``prod`` environment, visit the ``http://localhost:8000/app.php`` URL instead. +If you prefer to always show the ``dev`` environment in the URL, you can visit +``http://localhost:8000/app_dev.php`` URL. + +The main difference between environments is that ``dev`` is optimized to provide +lots of information to the developer, which means worse application performance. +Meanwhile, ``prod`` is optimized to get the best performance, which means that +debug information is disabled, as well as the Web Debug Toolbar. + +The other difference between environments is the configuration options used to +execute the application. When you access the ``dev`` environment, Symfony loads +the ``app/config/config_dev.yml`` configuration file. When you access the ``prod`` +environment, Symfony loads ``app/config/config_prod.yml`` file. + Typically, the environments share a large amount of configuration options. For that reason, you put your common configuration in ``config.yml`` and override the specific configuration file for each environment where necessary: @@ -362,29 +330,9 @@ the specific configuration file for each environment where necessary: toolbar: true intercept_redirects: false -In this example, the ``dev`` environment loads the ``config_dev.yml`` configuration -file, which itself imports the common ``config.yml`` file and then modifies it -by enabling the web debug toolbar. - -When you visit the ``app_dev.php`` file in your browser, you're executing -your Symfony application in the ``dev`` environment. To visit your application -in the ``prod`` environment, visit the ``app.php`` file instead. - -The demo routes in our application are only available in the ``dev`` environment. -Therefore, if you try to access the ``http://localhost/app.php/demo/hello/Fabien`` -URL, you'll get a 404 error. - -.. tip:: - - If instead of using PHP's built-in webserver, you use Apache with - ``mod_rewrite`` enabled and take advantage of the ``.htaccess`` file - Symfony provides in ``web/``, you can even omit the ``app.php`` part of the - URL. The default ``.htaccess`` points all requests to the ``app.php`` front - controller: - - .. code-block:: text - - http://localhost/demo/hello/Fabien +In this example, the ``config_dev.yml`` configuration file imports the common +``config.yml`` file and then overrides any existing web debug toolbar configuration +with its own options. For more details on environments, see ":ref:`Environments & Front Controllers `" article. @@ -396,7 +344,7 @@ Congratulations! You've had your first taste of Symfony code. That wasn't so hard, was it? There's a lot more to explore, but you should already see how Symfony makes it really easy to implement web sites better and faster. If you are eager to learn more about Symfony, dive into the next section: -":doc:`The View`". +":doc:`The View `". .. _Composer: https://getcomposer.org/ .. _executable installer: http://getcomposer.org/download diff --git a/quick_tour/the_controller.rst b/quick_tour/the_controller.rst index decb50b98a7..376a8d25dc9 100644 --- a/quick_tour/the_controller.rst +++ b/quick_tour/the_controller.rst @@ -1,8 +1,100 @@ The Controller ============== -Still here after the first two parts? You are already becoming a Symfony -addict! Without further ado, discover what controllers can do for you. +Still here after the first two parts? You are already becoming a Symfony fan! +Without further ado, discover what controllers can do for you. + +Returning Raw Responses +----------------------- + +Symfony defines itself as a Request-Response framework. When the user makes a +request to your application, Symfony creates a ``Request`` object to encapsulate +all the information related to that request. Similarly, the result of executing +any action of any controller is the creation of a ``Response`` object which +Symfony uses to generate the HTML content returned to the user. + +So far, all the actions shown in this tutorial used the ``$this->render()`` +shortcut to return a rendered response as result. If case you need it, you can +also create a raw ``Response`` object to return any text content:: + + // src/AppBundle/Controller/DefaultController.php + namespace AppBundle\Controller; + + use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; + use Symfony\Bundle\FrameworkBundle\Controller\Controller; + use Symfony\Component\HttpFoundation\Response; + + class DefaultController extends Controller + { + /** + * @Route("/", name="homepage") + */ + public function indexAction() + { + return new Response('Welcome to Symfony!'); + } + } + +Route Parameters +---------------- + +Most of the time, the URLs of applications include variable parts on them. If you +are creating for example a blog application, the URL to display the articles should +include their title or some other unique identifier to let the application know +the exact article to display. + +In Symfony applications, the variable parts of the routes are enclosed in curly +braces (e.g. ``/blog/read/{article_title}/``). Each variable part is assigned a +unique name that can be used later in the controller to retrieve each value. + +Let's create a new action with route variables to show this feature in action. +Open the ``src/AppBundle/Controller/DefaultController.php`` file and add a new +method called ``helloAction`` with the following content:: + + // src/AppBundle/Controller/DefaultController.php + namespace AppBundle\Controller; + + use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; + use Symfony\Bundle\FrameworkBundle\Controller\Controller; + + class DefaultController extends Controller + { + // ... + + /** + * @Route("/hello/{name}", name="hello") + */ + public function helloAction($name) + { + return $this->render('default/hello.html.twig', array( + 'name' => $name + )); + } + } + +Open your browser and access the ``http://localhost:8000/hello/fabien`` URL to +see the result of executing this new action. Instead of the action result, you'll +see an error page. As you probably guessed, the cause of this error is that we're +trying to render a template (``default/hello.html.twig``) that doesn't exist yet. + +Create the new ``app/Resources/views/default/hello.html.twig`` template with the +following content: + +.. code-block:: html+jinja + + {# app/Resources/views/default/hello.html.twig #} + {% extends 'base.html.twig' %} + + {% block body %} +

Hi {{ name }}! Welcome to Symfony!

+ {% endblock %} + +Browse again the ``http://localhost:8000/hello/fabien`` URL and you'll see this +new template rendered with the information passed by the controller. If you +change the last part of the URL (e.g. ``http://localhost:8000/hello/thomas``) +and reload your browser, the page will display a different message. And if you +remove the last part of the URL (e.g. ``http://localhost:8000/hello``), Symfony +will display an error because the route expects a name and you haven't provided it. Using Formats ------------- @@ -10,86 +102,114 @@ Using Formats Nowadays, a web application should be able to deliver more than just HTML pages. From XML for RSS feeds or Web Services, to JSON for Ajax requests, there are plenty of different formats to choose from. Supporting those formats -in Symfony is straightforward. Tweak the route by adding a default value of -``xml`` for the ``_format`` variable:: +in Symfony is straightforward thanks to a special variable called ``_format`` +which stores the format requested by the user. - // src/Acme/DemoBundle/Controller/DemoController.php +Tweak the ``hello`` route by adding a new ``_format`` variable with ``html`` as +its default value:: + + // src/AppBundle/Controller/DefaultController.php use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; // ... /** - * @Route("/hello/{name}", defaults={"_format"="xml"}, name="_demo_hello") - * @Template() + * @Route("/hello/{name}.{_format}", defaults={"_format"="html"}, name="hello") */ - public function helloAction($name) + public function helloAction($name, $_format) { - return array('name' => $name); + return $this->render('default/hello.'.$_format.'.twig', array( + 'name' => $name + )); } -By using the request format (as defined by the special ``_format`` variable), -Symfony automatically selects the right template, here ``hello.xml.twig``: +Obviously, when you support several request formats, you have to provide a +tempalte for each of the supported formats. In this case, you should create a +new ``hello.xml.twig`` template:: .. code-block:: xml+php - + {{ name }} +Now, when you browse to ``http://localhost:8000/hello/fabien``, you'll see the +regular HTML page because ``html`` is the default format. When visiting +``http://localhost:8000/hello/fabien.html`` you'll get again the HTML page, this +time because you explicitely asked for the ``html`` format. Lastly, if you visit +``http://localhost:8000/hello/fabien.xml`` you'll see the new XML template rendered +in your browser. + That's all there is to it. For standard formats, Symfony will also -automatically choose the best ``Content-Type`` header for the response. If -you want to support different formats for a single action, use the ``{_format}`` -placeholder in the route path instead:: +automatically choose the best ``Content-Type`` header for the response. To +restrict the the formats supported by a given action, use the ``requirements`` +option of the ``@Route()`` annotation:: - // src/Acme/DemoBundle/Controller/DemoController.php + // src/AppBundle/Controller/DefaultController.php use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; // ... /** - * @Route( - * "/hello/{name}.{_format}", - * defaults = { "_format" = "html" }, + * @Route("/hello/{name}.{_format}", + * defaults = {"_format"="html"}, * requirements = { "_format" = "html|xml|json" }, - * name = "_demo_hello" + * name = "hello" * ) - * @Template() */ - public function helloAction($name) + public function helloAction($name, $_format) { - return array('name' => $name); + return $this->render('default/hello.'.$_format.'.twig', array( + 'name' => $name + )); } -The controller will now match URLs like ``/demo/hello/Fabien.xml`` or -``/demo/hello/Fabien.json``. - -The ``requirements`` entry defines regular expressions that variables must -match. In this example, if you try to request the ``/demo/hello/Fabien.js`` -resource, you will get a 404 HTTP error, as it does not match the ``_format`` -requirement. +The ``hello`` action will now match URLs like ``/hello/fabien.xml`` or +``/hello/fabien.json``, but it will show a 404 error if you try to get URLs +like ``/hello/fabien.js``, because the value of the ``_format`` variable doesn't +meet its requirements. Redirecting and Forwarding -------------------------- -If you want to redirect the user to another page, use the ``redirect()`` +If you want to redirect the user to another page, use the ``redirectToRoute()`` method:: - return $this->redirect($this->generateUrl('_demo_hello', array('name' => 'Lucas'))); + // src/AppBundle/Controller/DefaultController.php + class DefaultController extends Controller + { + /** + * @Route("/", name="homepage") + */ + public function indexAction() + { + return $this->redirectToRoute('hello', array('name' => 'Fabien')); + } + } -The ``generateUrl()`` is the same method as the ``path()`` function used in the +The ``redirectToRoute()`` is similar to the ``path()`` function used in the templates. It takes the route name and an array of parameters as arguments and returns the associated friendly URL. -You can also internally forward the action to another using the ``forward()`` -method:: +You can also internally forward the action to another action of the same or +different controller using the ``forward()`` method:: - return $this->forward('AcmeDemoBundle:Hello:fancy', array( - 'name' => $name, - 'color' => 'green' - )); + // src/AppBundle/Controller/DefaultController.php + class DefaultController extends Controller + { + /** + * @Route("/", name="homepage") + */ + public function indexAction() + { + return $this->forward('AppBundle:Blog:index', array( + 'name' => $name + ); + } + } Displaying Error Pages ---------------------- @@ -98,34 +218,73 @@ Errors will inevitably happen during the execution of every web application. In the case of ``404`` errors, Symfony includes a handy shortcut that you can use in your controllers:: - throw $this->createNotFoundException(); + // src/AppBundle/Controller/DefaultController.php + class DefaultController extends Controller + { + /** + * @Route("/", name="homepage") + */ + public function indexAction() + { + throw $this->createNotFoundException(); + } + } For ``500`` errors, just throw a regular PHP exception inside the controller and Symfony will transform it into a proper ``500`` error page:: - throw new \Exception('Something went wrong!'); + // src/AppBundle/Controller/DefaultController.php + class DefaultController extends Controller + { + /** + * @Route("/", name="homepage") + */ + public function indexAction() + { + throw new \Exception('Something went horribly wrong!'); + } + } Getting Information from the Request ------------------------------------ -Symfony automatically injects the ``Request`` object when the controller has an -argument that's type hinted with ``Symfony\Component\HttpFoundation\Request``:: +Sometimes your controllers need to access the information related to the user +request, such as his/her preferred language, IP address or the URL query parameters. +To get access to this information, add a new argument of type ``Request`` to the +action. The name of this new argument doesn't matter, but it must be preceded +by the ``Request`` type in order to work (don't forget to add the new ``use`` +statement that imports this ``Request`` class):: + + // src/AppBundle/Controller/DefaultController.php + namespace AppBundle\Controller; + use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; + use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Request; - public function indexAction(Request $request) + class DefaultController extends Controller { - $request->isXmlHttpRequest(); // is it an Ajax request? - - $request->getPreferredLanguage(array('en', 'fr')); - - $request->query->get('page'); // get a $_GET parameter - - $request->request->get('page'); // get a $_POST parameter + /** + * @Route("/", name="homepage") + */ + public function indexAction(Request $request) + { + // is it an Ajax request? + $isAjax = $request->isXmlHttpRequest(); + + // what's the preferred language of the user? + $language = $request->getPreferredLanguage(array('en', 'fr')); + + // get the value of a $_GET parameter + $pageName = $request->query->get('page'); + + // get the value of a $_POST parameter + $pageName = $request->request->get('page'); + } } -In a template, you can also access the ``Request`` object via the -``app.request`` variable: +In a template, you can also access the ``Request`` object via the special +``app.request`` variable automatically provided by Symfony: .. code-block:: html+jinja @@ -164,40 +323,21 @@ You can also store "flash messages" that will auto-delete after the next request They are useful when you need to set a success message before redirecting the user to another page (which will then show the message):: - // store a message for the very next request (in a controller) - $session->getFlashBag()->add('notice', 'Congratulations, your action succeeded!'); - -.. code-block:: html+jinja - - {# display the flash message in the template #} -
{{ app.session.flashbag.get('notice') }}
- -Caching Resources ------------------ + public function indexAction(Request $request) + { + // ... -As soon as your website starts to generate more traffic, you will want to -avoid generating the same resource again and again. Symfony uses HTTP cache -headers to manage resources cache. For simple caching strategies, use the -convenient ``@Cache()`` annotation:: + // store a message for the very next request + $this->addFlash('notice', 'Congratulations, your action succeeded!'); + } - use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; - use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; - use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache; +And you can display the flash message in the template like this: - /** - * @Route("/hello/{name}", name="_demo_hello") - * @Template() - * @Cache(maxage="86400") - */ - public function helloAction($name) - { - return array('name' => $name); - } +.. code-block:: html+jinja -In this example, the resource will be cached for a day (``86400`` seconds). -Resource caching is managed by Symfony itself. But because caching is managed -using standard HTTP cache headers, you can use Varnish or Squid without having -to modify a single line of code in your application. +
+ {{ app.session.flashbag.get('notice') }} +
Final Thoughts -------------- diff --git a/quick_tour/the_view.rst b/quick_tour/the_view.rst index 470cd51226e..f147df63825 100644 --- a/quick_tour/the_view.rst +++ b/quick_tour/the_view.rst @@ -3,27 +3,29 @@ The View After reading the first part of this tutorial, you have decided that Symfony was worth another 10 minutes. In this second part, you will learn more about -`Twig`_, the fast, flexible, and secure template engine for PHP. Twig makes your -templates more readable and concise; it also makes them more friendly for web -designers. +`Twig`_, the fast, flexible, and secure template engine for PHP applications. +Twig makes your templates more readable and concise; it also makes them more +friendly for web designers. Getting familiar with Twig -------------------------- The official `Twig documentation`_ is the best resource to learn everything -about this new template engine. This section just gives you a quick overview of +about this template engine. This section just gives you a quick overview of its main concepts. A Twig template is a text file that can generate any type of content (HTML, CSS, -JavaScript, XML, CSV, LaTeX, ...). Twig elements are separated from the rest of +JavaScript, XML, CSV, LaTeX, etc.) Twig elements are separated from the rest of the template contents using any of these delimiters: -* ``{{ ... }}``: prints the content of a variable or the result of an expression; +* ``{{ ... }}``: prints the content of a variable or the result of evaluating an + expression; * ``{% ... %}``: controls the logic of the template; it is used for example to execute ``for`` loops and ``if`` statements; -* ``{# ... #}``: allows including comments inside templates. +* ``{# ... #}``: allows including comments inside templates. Contrary to HTML + comments, they aren't included in the rendered template. Below is a minimal template that illustrates a few basics, using two variables ``page_title`` and ``navigation``, which would be passed into the template: @@ -46,34 +48,34 @@ Below is a minimal template that illustrates a few basics, using two variables -To render a template in Symfony, use the ``render`` method from within a controller -and pass the variables needed as an array using the optional second argument:: +To render a template in Symfony, use the ``render`` method from within a controller. +If the template needs variables to generate its contents, pass them as an array +using the second optional second argument:: - $this->render('AcmeDemoBundle:Demo:hello.html.twig', array( - 'name' => $name, + $this->render('default/index.html.twig', array( + 'variable_name' => 'variable_value', )); -Variables passed to a template can be strings, arrays, or even objects. Twig +Variables passed to a template can be strings, arrays or even objects. Twig abstracts the difference between them and lets you access "attributes" of a variable with the dot (``.``) notation. The following code listing shows how to -display the content of a variable depending on the type of the variable passed -by the controller: +display the content of a variable passed by the controller depending on its type: .. code-block:: jinja {# 1. Simple variables #} - {# array('name' => 'Fabien') #} + {# $this->render( ..., array('name' => 'Fabien') ) #} {{ name }} {# 2. Arrays #} - {# array('user' => array('name' => 'Fabien')) #} + {# $this->render( ..., array('user' => array('name' => 'Fabien')) ) #} {{ user.name }} {# alternative syntax for arrays #} {{ user['name'] }} {# 3. Objects #} - {# array('user' => new User('Fabien')) #} + {# $this->render( ..., array('user' => new User('Fabien')) ) #} {{ user.name }} {{ user.getName }} @@ -86,60 +88,63 @@ Decorating Templates More often than not, templates in a project share common elements, like the well-known header and footer. Twig solves this problem elegantly with a concept -called "template inheritance". This feature allows you to build a base "layout" -template that contains all the common elements of your site and defines "blocks" +called "template inheritance". This feature allows you to build a base template +that contains all the common elements of your site and defines "blocks" of contents that child templates can override. -The ``hello.html.twig`` template uses the ``extends`` tag to indicate that it -inherits from the common ``layout.html.twig`` template: +The ``index.html.twig`` template uses the ``extends`` tag to indicate that it +inherits from the ``base.html.twig`` template: .. code-block:: html+jinja - {# src/Acme/DemoBundle/Resources/views/Demo/hello.html.twig #} - {% extends "AcmeDemoBundle::layout.html.twig" %} + {# app/Resources/views/default/index.html.twig #} + {% extends 'base.html.twig' %} - {% block title "Hello " ~ name %} - - {% block content %} -

Hello {{ name }}!

+ {% block body %} +

Welcome to Symfony!

{% endblock %} -The ``AcmeDemoBundle::layout.html.twig`` notation sounds familiar, doesn't it? -It is the same notation used to reference a regular template. The ``::`` part -simply means that the controller element is empty, so the corresponding file -is directly stored under the ``Resources/views/`` directory of the bundle. - -Now, simplify the ``layout.html.twig`` template: +Open the ``app/Resources/views/base.html.twig`` file that corresponds to the +``base.html.twig`` template and you'll find the following Twig code: -.. code-block:: jinja +.. code-block:: html+jinja - {# src/Acme/DemoBundle/Resources/views/layout.html.twig #} -
- {% block content %} - {% endblock %} -
+ {# app/Resources/views/base.html.twig #} + + + + + {% block title %}Welcome!{% endblock %} + {% block stylesheets %}{% endblock %} + + + + {% block body %}{% endblock %} + {% block javascripts %}{% endblock %} + + The ``{% block %}`` tags tell the template engine that a child template may -override those portions of the template. In this example, the ``hello.html.twig`` -template overrides the ``content`` block, meaning that the "Hello Fabien" text -is rendered inside the ``
`` element. +override those portions of the template. In this example, the ``index.html.twig`` +template overrides the ``content`` block, but not the ``title`` block, which will +display the default content defined in the ``base.html.twig`` template. Using Tags, Filters, and Functions ---------------------------------- -One of the best feature of Twig is its extensibility via tags, filters, and +One of the best features of Twig is its extensibility via tags, filters, and functions. Take a look at the following sample template that uses filters extensively to modify the information before displaying it to the user: .. code-block:: jinja -

{{ article.title|trim|capitalize }}

+

{{ article.title|capitalize }}

-

{{ article.content|striptags|slice(0, 1024) }}

+

{{ article.content|striptags|slice(0, 255) }} ...

Tags: {{ article.tags|sort|join(", ") }}

-

Next article will be published on {{ 'next Monday'|date('M j, Y')}}

+

Activate your account before {{ 'next Monday'|date('M j, Y') }}

Don't forget to check out the official `Twig documentation`_ to learn everything about filters, functions and tags. @@ -150,23 +155,28 @@ Including other Templates The best way to share a snippet of code between several templates is to create a new template fragment that can then be included from other templates. -First, create an ``embedded.html.twig`` template: +Imagine that we want to display ads on some pages of our application. First, +create an ``banner.html.twig`` template: .. code-block:: jinja - {# src/Acme/DemoBundle/Resources/views/Demo/embedded.html.twig #} - Hello {{ name }} + {# app/Resources/views/ads/banner.html.twig #} +
+ ... +
-And change the ``hello.html.twig`` template to include it: +To display this ad on any page, include the ``banner.html.twig`` template using +the ``include()`` function: -.. code-block:: jinja +.. code-block:: html+jinja + + {# app/Resources/views/default/index.html.twig #} + {% extends 'base.html.twig' %} - {# src/Acme/DemoBundle/Resources/views/Demo/hello.html.twig #} - {% extends "AcmeDemoBundle::layout.html.twig" %} + {% block body %} +

Welcome to Symfony!

- {# override the body block from embedded.html.twig #} - {% block content %} - {{ include("AcmeDemoBundle:Demo:embedded.html.twig") }} + {{ include('ads/banner.html.twig') }} {% endblock %} Embedding other Controllers @@ -178,28 +188,28 @@ some variable not available in the main template. Suppose you've created a ``topArticlesAction`` controller method to display the most popular articles of your website. If you want to "render" the result of -that method (e.g. ``HTML``) inside the ``index`` template, use the ``render`` -function: +that method (usually some HTML content) inside the ``index`` template, use the +``render()`` function: .. code-block:: jinja - {# src/Acme/DemoBundle/Resources/views/Demo/index.html.twig #} - {{ render(controller("AcmeDemoBundle:Demo:topArticles", {'num': 10})) }} + {# app/Resources/views/index.html.twig #} + {{ render(controller('AppBundle:Default:topArticles')) }} -Here, the ``AcmeDemoBundle:Demo:topArticles`` string refers to the -``topArticlesAction`` action of the ``Demo`` controller, and the ``num`` -argument is made available to the controller:: +Here, the ``render()`` and ``controller()`` functions use the special +``AppBundle:Default:topArticles`` syntax to refer to the ``topArticlesAction`` +action of the ``Default`` controller (the ``AppBundle`` part will be explained later):: - // src/Acme/DemoBundle/Controller/DemoController.php + // src/AppBundle/Controller/DefaultController.php - class DemoController extends Controller + class DefaultController extends Controller { - public function topArticlesAction($num) + public function topArticlesAction() { - // look for the $num most popular articles in the database + // look for the most popular articles in the database $articles = ...; - return $this->render('AcmeDemoBundle:Demo:topArticles.html.twig', array( + return $this->render('default/top_articles.html.twig', array( 'articles' => $articles, )); } @@ -217,32 +227,16 @@ updated by just changing the configuration: .. code-block:: html+jinja - Greet Thomas! - -The ``path`` function takes the route name and an array of parameters as -arguments. The route name is the key under which routes are defined and the -parameters are the values of the variables defined in the route pattern:: + Return to homepage - // src/Acme/DemoBundle/Controller/DemoController.php - use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; - use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; - - // ... - - /** - * @Route("/hello/{name}", name="_demo_hello") - * @Template() - */ - public function helloAction($name) - { - return array('name' => $name); - } +The ``path`` function takes the route name as the first argument and optionally +you can pass an array of route parameters as the second argument. .. tip:: The ``url`` function is very similar to the ``path`` function, but generates *absolute* URLs, which is very handy when rendering emails and RSS files: - ``{{ url('_demo_hello', {'name': 'Thomas'}) }}``. + ``Visit our website``. Including Assets: Images, JavaScripts and Stylesheets ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -256,18 +250,20 @@ Symfony provides the ``asset`` function to deal with them easily: -The ``asset`` function's main purpose is to make your application more portable. -Thanks to this function, you can move the application root directory anywhere -under your web root directory without changing anything in your template's -code. +The ``asset()`` function looks for the web assets inside the ``web/`` directory. +If you store them in other directory, read ..... this article to learn how to +manage web assets. + +Using the ``asset`` function, your application is more portable. The reason is +that you can move the application root directory anywhere under your web root +directory without changing anything in your template's code. Final Thoughts -------------- Twig is simple yet powerful. Thanks to layouts, blocks, templates and action inclusions, it is very easy to organize your templates in a logical and -extensible way. However, if you're not comfortable with Twig, you can always -use PHP templates inside Symfony without any issues. +extensible way. You have only been working with Symfony for about 20 minutes, but you can already do pretty amazing stuff with it. That's the power of Symfony. Learning @@ -278,5 +274,5 @@ But I'm getting ahead of myself. First, you need to learn more about the control and that's exactly the topic of the :doc:`next part of this tutorial `. Ready for another 10 minutes with Symfony? -.. _Twig: http://twig.sensiolabs.org/ +.. _Twig: http://twig.sensiolabs.org/ .. _Twig documentation: http://twig.sensiolabs.org/documentation From 6105acb457d0dcd582ed2b2e9eb11b825062d438 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 25 Oct 2014 19:38:43 +0200 Subject: [PATCH 2/4] Fixed a RST formatting issue --- quick_tour/the_controller.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quick_tour/the_controller.rst b/quick_tour/the_controller.rst index 376a8d25dc9..21de0aa1770 100644 --- a/quick_tour/the_controller.rst +++ b/quick_tour/the_controller.rst @@ -126,7 +126,7 @@ its default value:: Obviously, when you support several request formats, you have to provide a tempalte for each of the supported formats. In this case, you should create a -new ``hello.xml.twig`` template:: +new ``hello.xml.twig`` template: .. code-block:: xml+php From 940924c459aa9630a8ca98c1b72500365b071b58 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 1 Nov 2014 19:48:01 +0100 Subject: [PATCH 3/4] Added a bunch of fixes suggested by @xabbuh --- quick_tour/the_architecture.rst | 6 +++--- quick_tour/the_big_picture.rst | 28 +++++++++++++++------------- quick_tour/the_controller.rst | 17 +++++++++-------- quick_tour/the_view.rst | 12 ++++++------ 4 files changed, 33 insertions(+), 30 deletions(-) diff --git a/quick_tour/the_architecture.rst b/quick_tour/the_architecture.rst index 9667fee3d70..b92d7d62f1f 100644 --- a/quick_tour/the_architecture.rst +++ b/quick_tour/the_architecture.rst @@ -122,7 +122,7 @@ a single ``Bundle`` class that describes it:: In addition to the AppBundle that was already talked about, notice that the kernel also enables other bundles such as the FrameworkBundle, DoctrineBundle, -SwiftmailerBundle and AsseticBundle bundle. They are all part of the core framework. +SwiftmailerBundle and AsseticBundle. They are all part of the core framework. Configuring a Bundle ~~~~~~~~~~~~~~~~~~~~ @@ -213,7 +213,7 @@ the location of the AppBundle. Logical Controller Names ........................ -For controllers, you need to reference action using the format +For controllers, you need to reference actions using the format ``BUNDLE_NAME:CONTROLLER_NAME:ACTION_NAME``. For instance, ``AppBundle:Default:index`` maps to the ``indexAction`` method from the ``AppBundle\Controller\DefaultController`` class. @@ -240,7 +240,7 @@ Using Vendors Odds are that your application will depend on third-party libraries. Those should be stored in the ``vendor/`` directory and managed by Composer. This directory already contains the Symfony libraries, the SwiftMailer library, -the Doctrine ORM, the Twig templating system, and some other third party +the Doctrine ORM, the Twig templating system and some other third party libraries and bundles. Understanding the Cache and Logs diff --git a/quick_tour/the_big_picture.rst b/quick_tour/the_big_picture.rst index c1a1493e62f..4390cc0a0d2 100644 --- a/quick_tour/the_big_picture.rst +++ b/quick_tour/the_big_picture.rst @@ -16,7 +16,7 @@ to display the installed PHP version: .. code-block:: bash - php --version + $ php --version .. _installing-symfony2: @@ -37,12 +37,13 @@ On **Linux** and **Mac OS X** systems, execute the following console commands: .. note:: - If your system doesn't have cURL installed, execute instead the following - command: + If your system doesn't have cURL installed, execute the following + commands instead: .. code-block:: bash $ php -r "readfile('https://symfony.com/installer');" | php + $ sudo mv symfony.phar /usr/local/bin/symfony After installing the Symfony installer, you'll have to open a new console window to be able to execute the new ``symfony`` command: @@ -214,16 +215,17 @@ A **PHP annotation** is a convenient way to configure a method without having to write regular PHP code. Beware that annotation blocks start with ``/**``, whereas regular PHP comments start with ``/*``. -The first value of ``@Route()`` defines the path that will trigger the execution -of the action. This path is configured via a relative URL, so you don't have to -add the host of your application (e.g. ```http://example.com``). In this case, -the value ``/`` refers to the application homepage. The second value of ``@Route()`` -(e.g. ``name="homepage"``) is optional and sets the name of this route. For now -this name is not needed, but later it'll be useful for linking pages. +The first value of ``@Route()`` defines the URL that will trigger the execution +of the action. As you don't have to add the host of your application to the URL +(e.g. ```http://example.com``), these URLs are always relative and they are usually +called *paths*. In this case, the ``/`` path refers to the application homepage. +The second value of ``@Route()`` (e.g. ``name="homepage"``) is optional and sets +the name of this route. For now this name is not needed, but later it'll be useful +for linking pages. Considering all this, the ``@Route("/", name="homepage")`` annotation creates a new route called ``homepage`` which makes Symfony execute the ``index`` action -of the ``Default`` controller when the users browses the ``/`` URL of the application. +of the ``Default`` controller when the user browses the ``/`` path of the application. .. tip:: @@ -259,7 +261,7 @@ the following code: {% endblock %} This template is created with `Twig`_, a new template engine created for modern -PHP applications. The :doc:`second part of this tutorial` +PHP applications. The :doc:`second part of this tutorial ` will introduce how templates work in Symfony. .. _quick-tour-big-picture-environments: @@ -287,8 +289,8 @@ may be worried about your visitors accessing sensible information. Symfony is aware of this issue and for that reason, it won't display this bar when your application is running in the production server. -How does Symfony knows when is your application running locally or in a production -server? Keep reading to discover the concept of **execution environments**. +How does Symfony know whether your application is running locally or on a +production server? Keep reading to discover the concept of **execution environments**. .. _quick-tour-big-picture-environments-intro: diff --git a/quick_tour/the_controller.rst b/quick_tour/the_controller.rst index 21de0aa1770..0f593f3a356 100644 --- a/quick_tour/the_controller.rst +++ b/quick_tour/the_controller.rst @@ -14,7 +14,7 @@ any action of any controller is the creation of a ``Response`` object which Symfony uses to generate the HTML content returned to the user. So far, all the actions shown in this tutorial used the ``$this->render()`` -shortcut to return a rendered response as result. If case you need it, you can +shortcut to return a rendered response as result. In case you need it, you can also create a raw ``Response`` object to return any text content:: // src/AppBundle/Controller/DefaultController.php @@ -125,7 +125,7 @@ its default value:: } Obviously, when you support several request formats, you have to provide a -tempalte for each of the supported formats. In this case, you should create a +template for each of the supported formats. In this case, you should create a new ``hello.xml.twig`` template: .. code-block:: xml+php @@ -144,7 +144,7 @@ in your browser. That's all there is to it. For standard formats, Symfony will also automatically choose the best ``Content-Type`` header for the response. To -restrict the the formats supported by a given action, use the ``requirements`` +restrict the formats supported by a given action, use the ``requirements`` option of the ``@Route()`` annotation:: // src/AppBundle/Controller/DefaultController.php @@ -190,9 +190,8 @@ method:: } } -The ``redirectToRoute()`` is similar to the ``path()`` function used in the -templates. It takes the route name and an array of parameters as arguments and -returns the associated friendly URL. +The ``redirectToRoute()`` method takes as arguments the route name and an optional +array of parameters and redirects the user to the URL generated with those arguments. You can also internally forward the action to another action of the same or different controller using the ``forward()`` method:: @@ -226,6 +225,7 @@ use in your controllers:: */ public function indexAction() { + // ... throw $this->createNotFoundException(); } } @@ -241,6 +241,7 @@ Symfony will transform it into a proper ``500`` error page:: */ public function indexAction() { + // ... throw new \Exception('Something went horribly wrong!'); } } @@ -249,7 +250,7 @@ Getting Information from the Request ------------------------------------ Sometimes your controllers need to access the information related to the user -request, such as his/her preferred language, IP address or the URL query parameters. +request, such as their preferred language, IP address or the URL query parameters. To get access to this information, add a new argument of type ``Request`` to the action. The name of this new argument doesn't matter, but it must be preceded by the ``Request`` type in order to work (don't forget to add the new ``use`` @@ -346,4 +347,4 @@ That's all there is to it, and I'm not even sure you'll have spent the full 10 minutes. You were briefly introduced to bundles in the first part, and all the features you've learned about so far are part of the core framework bundle. But thanks to bundles, everything in Symfony can be extended or replaced. -That's the topic of the :doc:`next part of this tutorial`. +That's the topic of the :doc:`next part of this tutorial `. diff --git a/quick_tour/the_view.rst b/quick_tour/the_view.rst index f147df63825..4b16967bd81 100644 --- a/quick_tour/the_view.rst +++ b/quick_tour/the_view.rst @@ -50,7 +50,7 @@ Below is a minimal template that illustrates a few basics, using two variables To render a template in Symfony, use the ``render`` method from within a controller. If the template needs variables to generate its contents, pass them as an array -using the second optional second argument:: +using the second optional argument:: $this->render('default/index.html.twig', array( 'variable_name' => 'variable_value', @@ -156,7 +156,7 @@ The best way to share a snippet of code between several templates is to create a new template fragment that can then be included from other templates. Imagine that we want to display ads on some pages of our application. First, -create an ``banner.html.twig`` template: +create a ``banner.html.twig`` template: .. code-block:: jinja @@ -229,8 +229,8 @@ updated by just changing the configuration: Return to homepage -The ``path`` function takes the route name as the first argument and optionally -you can pass an array of route parameters as the second argument. +The ``path`` function takes the route name as the first argument and you can +optionally pass an array of route parameters as the second argument. .. tip:: @@ -251,8 +251,8 @@ Symfony provides the ``asset`` function to deal with them easily: The ``asset()`` function looks for the web assets inside the ``web/`` directory. -If you store them in other directory, read ..... this article to learn how to -manage web assets. +If you store them in another directory, read :doc:`this article ` +to learn how to manage web assets. Using the ``asset`` function, your application is more portable. The reason is that you can move the application root directory anywhere under your web root From 811f6e8139d7127f61107b7fffacd672612f482e Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 12 Nov 2014 10:21:08 +0100 Subject: [PATCH 4/4] Included a bunch of fixes suggested by the awesome Symfony doc reviewers --- quick_tour/the_architecture.rst | 16 +++++++------- quick_tour/the_big_picture.rst | 37 ++++++++++++++++++++------------- quick_tour/the_controller.rst | 4 ++++ quick_tour/the_view.rst | 8 +++---- 4 files changed, 38 insertions(+), 27 deletions(-) diff --git a/quick_tour/the_architecture.rst b/quick_tour/the_architecture.rst index b92d7d62f1f..b3fab62cf1c 100644 --- a/quick_tour/the_architecture.rst +++ b/quick_tour/the_architecture.rst @@ -13,7 +13,7 @@ Understanding the Directory Structure The directory structure of a Symfony :term:`application` is rather flexible, but the recommended structure is as follows: -* ``app/``: the application configuration and templates; +* ``app/``: the application configuration, templates and translations; * ``src/``: the project's PHP code; * ``vendor/``: the third-party dependencies; * ``web/``: the web root directory. @@ -121,8 +121,8 @@ a single ``Bundle`` class that describes it:: } In addition to the AppBundle that was already talked about, notice that the -kernel also enables other bundles such as the FrameworkBundle, DoctrineBundle, -SwiftmailerBundle and AsseticBundle. They are all part of the core framework. +kernel also enables other bundles that are part of Symfony, such as FrameworkBundle, +DoctrineBundle, SwiftmailerBundle and AsseticBundle. Configuring a Bundle ~~~~~~~~~~~~~~~~~~~~ @@ -168,7 +168,7 @@ PHP. Have a look at this sample of the default Symfony configuration: # ... -Each first level entry like ``framework``, ``twig`` or ``swiftmailer`` defines +Each first level entry like ``framework``, ``twig`` and ``swiftmailer`` defines the configuration for a specific bundle. For example, ``framework`` configures the FrameworkBundle while ``swiftmailer`` configures the SwiftmailerBundle. @@ -238,10 +238,10 @@ Using Vendors ------------- Odds are that your application will depend on third-party libraries. Those -should be stored in the ``vendor/`` directory and managed by Composer. -This directory already contains the Symfony libraries, the SwiftMailer library, -the Doctrine ORM, the Twig templating system and some other third party -libraries and bundles. +should be stored in the ``vendor/`` directory. You should never touch anything +in this directory, because it is exclusively managed by Composer. This directory +already contains the Symfony libraries, the SwiftMailer library, the Doctrine ORM, +the Twig templating system and some other third party libraries and bundles. Understanding the Cache and Logs -------------------------------- diff --git a/quick_tour/the_big_picture.rst b/quick_tour/the_big_picture.rst index 4390cc0a0d2..be24e7ecfaf 100644 --- a/quick_tour/the_big_picture.rst +++ b/quick_tour/the_big_picture.rst @@ -23,10 +23,9 @@ to display the installed PHP version: Installing Symfony ------------------ -In the past, Symfony had to be installed manually for each new project. In order -to simplify this set up, a new **Symfony Installer** was introduced recently. -This means that the very first time you use Symfony on a computer, you have to -install the Symfony Installer. +In the past, Symfony had to be installed manually for each new project. Now you +can use the **Symfony Installer**, which has to be installed the very first time +you use Symfony on a computer. On **Linux** and **Mac OS X** systems, execute the following console commands: @@ -52,9 +51,15 @@ to be able to execute the new ``symfony`` command: $ symfony -On **Windows** systems, download the ``symfony.phar`` file from ........... and -save it into the directory where you create the Symfony projects. Then you can -execute the Symfony installer right away with this command: +On **Windows** systems, execute the following console command: + + .. code-block:: bash + + c:\> php -r "readfile('https://symfony.com/installer');" | php + +This command downloads a file called ``symfony.phar`` which contains the Symfony +installer. Save or move that file to the directory where you create the Symfony +projects and then, execute the Symfony installer right away with this command: .. code-block:: bash @@ -90,7 +95,7 @@ the project directory and executing this command: .. code-block:: bash $ cd myproject/ - $ php app/console server:start + $ php app/console server:run Open your browser and access the ``http://localhost:8000`` URL to see the Welcome page of Symfony: @@ -166,9 +171,9 @@ that will be explained in the next section):: } } -In Symfony applications, **controllers** are PHP classes whose names are suffixed -with the ``Controller`` word. In this example, the controller is called ``Default`` -and the PHP class is called ``DefaultController``. +In Symfony applications, **controllers** are usually PHP classes whose names are +suffixed with the ``Controller`` word. In this example, the controller is called +``Default`` and the PHP class is called ``DefaultController``. The methods defined in a controller are called **actions**, they are usually associated with one URL of the application and their names are suffixed with @@ -230,8 +235,9 @@ of the ``Default`` controller when the user browses the ``/`` path of the applic .. tip:: In addition to PHP annotations, routes can be configured in YAML, XML or - PHP files. This flexibility is one of the main features of Symfony, a - framework that never imposes a particular configuration format on you. + PHP files, as explained in `the Routing chapter of the Symfony book`_ . + This flexibility is one of the main features of Symfony, a framework that + never imposes a particular configuration format on you. Templates ~~~~~~~~~ @@ -348,6 +354,7 @@ Symfony makes it really easy to implement web sites better and faster. If you are eager to learn more about Symfony, dive into the next section: ":doc:`The View `". -.. _Composer: https://getcomposer.org/ +.. _Composer: https://getcomposer.org/ .. _executable installer: http://getcomposer.org/download -.. _Twig: http://twig.sensiolabs.org/ +.. _Twig: http://twig.sensiolabs.org/ +.. _the Routing chapter of the Symfony book: http://symfony.com/doc/current/book/routing.html diff --git a/quick_tour/the_controller.rst b/quick_tour/the_controller.rst index 0f593f3a356..e669bb734e5 100644 --- a/quick_tour/the_controller.rst +++ b/quick_tour/the_controller.rst @@ -218,6 +218,8 @@ In the case of ``404`` errors, Symfony includes a handy shortcut that you can use in your controllers:: // src/AppBundle/Controller/DefaultController.php + // ... + class DefaultController extends Controller { /** @@ -234,6 +236,8 @@ For ``500`` errors, just throw a regular PHP exception inside the controller and Symfony will transform it into a proper ``500`` error page:: // src/AppBundle/Controller/DefaultController.php + // ... + class DefaultController extends Controller { /** diff --git a/quick_tour/the_view.rst b/quick_tour/the_view.rst index 4b16967bd81..a8741123837 100644 --- a/quick_tour/the_view.rst +++ b/quick_tour/the_view.rst @@ -64,18 +64,18 @@ display the content of a variable passed by the controller depending on its type .. code-block:: jinja {# 1. Simple variables #} - {# $this->render( ..., array('name' => 'Fabien') ) #} + {# $this->render('template.html.twig', array('name' => 'Fabien') ) #} {{ name }} {# 2. Arrays #} - {# $this->render( ..., array('user' => array('name' => 'Fabien')) ) #} + {# $this->render('template.html.twig', array('user' => array('name' => 'Fabien')) ) #} {{ user.name }} {# alternative syntax for arrays #} {{ user['name'] }} {# 3. Objects #} - {# $this->render( ..., array('user' => new User('Fabien')) ) #} + {# $this->render('template.html.twig', array('user' => new User('Fabien')) ) #} {{ user.name }} {{ user.getName }} @@ -251,7 +251,7 @@ Symfony provides the ``asset`` function to deal with them easily: The ``asset()`` function looks for the web assets inside the ``web/`` directory. -If you store them in another directory, read :doc:`this article ` +If you store them in another directory, read :doc:`this article ` to learn how to manage web assets. Using the ``asset`` function, your application is more portable. The reason is