-
-
Notifications
You must be signed in to change notification settings - Fork 5.2k
[WCM] Revamped the Quick Start tutorial #4374
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
531fc24
4725c16
fe20efd
1ca388e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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, templates and translations; | ||
* ``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 | ||
|
||
|
@@ -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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. implement (it refers to files, doesn't it?) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the same phrase use originally in the tutorial. I think it's correct because "implements" refers to the bundle, not the files. But maybe the wording is confusing and we could change it. What do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's fine so. |
||
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,23 +120,23 @@ 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 that are part of Symfony, such as FrameworkBundle, | ||
DoctrineBundle, SwiftmailerBundle and AsseticBundle. | ||
|
||
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 | ||
|
||
# app/config/config.yml | ||
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`` and ``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,64 +191,42 @@ 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 | ||
~~~~~~~~~~~~~~~~~~ | ||
|
||
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 | ||
.................. | ||
|
||
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 actions 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</cookbook/bundles/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 </cookbook/bundles/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. 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 | ||
-------------------------------- | ||
|
||
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we need to add a caution somewhere (not sure quick tour is the best place) that the cache clearing done by |
||
|
||
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 | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this first sentence puts people on the wrong path. It'll put beginners in the limited view of: If something is not in bundle, it won't work with Symfony.
In fact, almost everythig can live outside the bundle and it's a good practice to use a bundle only to integrate a library.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is the quick tour, we need to keep things on the simpler side. We could have people put their integration code in a bundle and their model-ish code just in a namespaced directory in
src/
. That would be a really nice practice. But you need some experience before knowing what should live where (otherwise it's just another choice that a new dev has to make). For a new developer, they'll be putting things inapp/
or in a bundle (insrc/
).BUT, I do think this sentence is a bit out-dated. The bundle (or technically
src/
directory) of an application is now mostly for PHP classes - other things (e.g. stylesheets) should live elsewhere. So do think we can tweak this a little bit.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now I see we have a sentence below about how you could later split your
AppBundle
into re-usable components or bundles. So it sounds like we're trying to talk a bit here about the philosophy of re-usable bundles. I think I'll have to re-read this section to make sure we're being totally clear.