Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch '2.1'

  • Loading branch information...
commit dccf1238fa829a019700ddb69a33eba30f80b59b 2 parents 30d49c7 + a03f06f
@weaverryan weaverryan authored
Showing with 376 additions and 143 deletions.
  1. +23 −8 book/controller.rst
  2. +8 −3 book/doctrine.rst
  3. +3 −1 book/forms.rst
  4. +16 −4 book/from_flat_php_to_symfony2.rst
  5. +11 −3 book/page_creation.rst
  6. +1 −1  book/performance.rst
  7. +6 −2 book/propel.rst
  8. +20 −5 book/routing.rst
  9. +11 −6 book/security.rst
  10. +21 −5 book/service_container.rst
  11. +18 −5 book/templating.rst
  12. +31 −9 book/testing.rst
  13. +16 −4 book/translation.rst
  14. +14 −8 book/validation.rst
  15. +1 −1  components/http_foundation/introduction.rst
  16. +2 −2 cookbook/assetic/asset_management.rst
  17. +43 −14 cookbook/console/console_command.rst
  18. +3 −3 cookbook/deployment-tools.rst
  19. +25 −9 cookbook/doctrine/file_uploads.rst
  20. +11 −8 cookbook/doctrine/multiple_entity_managers.rst
  21. +18 −5 cookbook/doctrine/registration_form.rst
  22. +9 −4 cookbook/email/dev_environment.rst
  23. +6 −1 cookbook/email/email.rst
  24. +6 −10 cookbook/form/dynamic_form_generation.rst
  25. +4 −2 cookbook/form/form_collections.rst
  26. +15 −12 cookbook/map.rst.inc
  27. +1 −1  cookbook/security/acl.rst
  28. +4 −1 cookbook/testing/doctrine.rst
  29. +12 −3 cookbook/testing/profiling.rst
  30. +1 −1  reference/forms/types/collection.rst
  31. +3 −1 reference/forms/types/form.rst
  32. +7 −0 reference/forms/types/options/mapped.rst.inc
  33. +6 −1 reference/forms/types/options/property_path.rst.inc
View
31 book/controller.rst
@@ -472,10 +472,13 @@ value to each variable.
object::
$httpKernel = $this->container->get('http_kernel');
- $response = $httpKernel->forward('AcmeHelloBundle:Hello:fancy', array(
- 'name' => $name,
- 'color' => 'green',
- ));
+ $response = $httpKernel->forward(
+ 'AcmeHelloBundle:Hello:fancy',
+ array(
+ 'name' => $name,
+ 'color' => 'green',
+ )
+ );
.. index::
single: Controller; Rendering templates
@@ -490,14 +493,20 @@ that's responsible for generating the HTML (or other format) for the controller.
The ``renderView()`` method renders a template and returns its content. The
content from the template can be used to create a ``Response`` object::
- $content = $this->renderView('AcmeHelloBundle:Hello:index.html.twig', array('name' => $name));
+ $content = $this->renderView(
+ 'AcmeHelloBundle:Hello:index.html.twig',
+ array('name' => $name)
+ );
return new Response($content);
This can even be done in just one step with the ``render()`` method, which
returns a ``Response`` object containing the content from the template::
- return $this->render('AcmeHelloBundle:Hello:index.html.twig', array('name' => $name));
+ return $this->render(
+ 'AcmeHelloBundle:Hello:index.html.twig',
+ array('name' => $name)
+ );
In both cases, the ``Resources/views/Hello/index.html.twig`` template inside
the ``AcmeHelloBundle`` will be rendered.
@@ -517,7 +526,10 @@ The Symfony templating engine is explained in great detail in the
service. The ``templating`` service can also be used directly::
$templating = $this->get('templating');
- $content = $templating->render('AcmeHelloBundle:Hello:index.html.twig', array('name' => $name));
+ $content = $templating->render(
+ 'AcmeHelloBundle:Hello:index.html.twig',
+ array('name' => $name)
+ );
.. note::
@@ -525,7 +537,10 @@ The Symfony templating engine is explained in great detail in the
be careful to avoid the pitfall of making your directory structure unduly
elaborate::
- $templating->render('AcmeHelloBundle:Hello/Greetings:index.html.twig', array('name' => $name));
+ $templating->render(
+ 'AcmeHelloBundle:Hello/Greetings:index.html.twig',
+ array('name' => $name)
+ );
// index.html.twig found in Resources/views/Hello/Greetings is rendered.
.. index::
View
11 book/doctrine.rst
@@ -472,7 +472,9 @@ on its ``id`` value::
->find($id);
if (!$product) {
- throw $this->createNotFoundException('No product found for id '.$id);
+ throw $this->createNotFoundException(
+ 'No product found for id '.$id
+ );
}
// ... do something, like pass the $product object into a template
@@ -557,7 +559,9 @@ you have a route that maps a product id to an update action in a controller::
$product = $em->getRepository('AcmeStoreBundle:Product')->find($id);
if (!$product) {
- throw $this->createNotFoundException('No product found for id '.$id);
+ throw $this->createNotFoundException(
+ 'No product found for id '.$id
+ );
}
$product->setName('New product name!');
@@ -1308,7 +1312,8 @@ and ``nullable``. Take a few examples:
/**
* A string field with length 255 that cannot be null
- * (reflecting the default values for the "type", "length" and *nullable* options)
+ * (reflecting the default values for the "type", "length"
+ * and *nullable* options)
*
* @ORM\Column()
*/
View
4 book/forms.rst
@@ -1565,7 +1565,9 @@ method to specify the option::
{
$collectionConstraint = new Collection(array(
'name' => new Length(array("min" => 5)),
- 'email' => new Email(array('message' => 'Invalid email address')),
+ 'email' => new Email(
+ array('message' => 'Invalid email address')
+ ),
));
$resolver->setDefaults(array(
View
20 book/from_flat_php_to_symfony2.rst
@@ -554,7 +554,10 @@ them for you. Here's the same sample application, now built in Symfony2::
->createQuery('SELECT p FROM AcmeBlogBundle:Post p')
->execute();
- return $this->render('AcmeBlogBundle:Blog:list.html.php', array('posts' => $posts));
+ return $this->render(
+ 'AcmeBlogBundle:Blog:list.html.php',
+ array('posts' => $posts)
+ );
}
public function showAction($id)
@@ -570,7 +573,10 @@ them for you. Here's the same sample application, now built in Symfony2::
throw $this->createNotFoundException();
}
- return $this->render('AcmeBlogBundle:Blog:show.html.php', array('post' => $post));
+ return $this->render(
+ 'AcmeBlogBundle:Blog:show.html.php',
+ array('post' => $post)
+ );
}
}
@@ -590,7 +596,10 @@ now quite a bit simpler:
<ul>
<?php foreach ($posts as $post): ?>
<li>
- <a href="<?php echo $view['router']->generate('blog_show', array('id' => $post->getId())) ?>">
+ <a href="<?php echo $view['router']->generate(
+ 'blog_show',
+ array('id' => $post->getId())
+ ) ?>">
<?php echo $post->getTitle() ?>
</a>
</li>
@@ -605,7 +614,10 @@ The layout is nearly identical:
<!DOCTYPE html>
<html>
<head>
- <title><?php echo $view['slots']->output('title', 'Default title') ?></title>
+ <title><?php echo $view['slots']->output(
+ 'title',
+ 'Default title'
+ ) ?></title>
</head>
<body>
<?php echo $view['slots']->output('_content') ?>
View
14 book/page_creation.rst
@@ -288,10 +288,16 @@ of writing the HTML inside the controller, render a template instead:
{
public function indexAction($name)
{
- return $this->render('AcmeHelloBundle:Hello:index.html.twig', array('name' => $name));
+ return $this->render(
+ 'AcmeHelloBundle:Hello:index.html.twig',
+ array('name' => $name)
+ );
// render a PHP template instead
- // return $this->render('AcmeHelloBundle:Hello:index.html.php', array('name' => $name));
+ // return $this->render(
+ // 'AcmeHelloBundle:Hello:index.html.php',
+ // array('name' => $name)
+ // );
}
}
@@ -903,7 +909,9 @@ file of your choice::
// app/AppKernel.php
public function registerContainerConfiguration(LoaderInterface $loader)
{
- $loader->load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml');
+ $loader->load(
+ __DIR__.'/config/config_'.$this->getEnvironment().'.yml'
+ );
}
You already know that the ``.yml`` extension can be changed to ``.xml`` or
View
2  book/performance.rst
@@ -56,7 +56,7 @@ finally finds the file it's looking for.
The simplest solution is to tell Composer to build a "class map" (i.e. a
big array of the locations of all the classes). This can be done from the
-command line, and might become part of your deploy process::
+command line, and might become part of your deploy process:
.. code-block:: bash
View
8 book/propel.rst
@@ -181,7 +181,9 @@ value::
->findPk($id);
if (!$product) {
- throw $this->createNotFoundException('No product found for id '.$id);
+ throw $this->createNotFoundException(
+ 'No product found for id '.$id
+ );
}
// ... do something, like pass the $product object into a template
@@ -202,7 +204,9 @@ have a route that maps a product id to an update action in a controller::
->findPk($id);
if (!$product) {
- throw $this->createNotFoundException('No product found for id '.$id);
+ throw $this->createNotFoundException(
+ 'No product found for id '.$id
+ );
}
$product->setName('New product name!');
View
25 book/routing.rst
@@ -417,7 +417,7 @@ match, giving the ``page`` parameter a value of ``2``. Perfect.
.. tip::
- Routes with optional parameters at the end will not match on requests
+ Routes with optional parameters at the end will not match on requests
with a trailing slash (i.e. ``/blog/`` will not match, ``/blog`` will match).
.. index::
@@ -787,6 +787,12 @@ a slash. URLs matching this route might look like:
each value of ``_format``. The ``_format`` parameter is a very powerful way
to render the same content in different formats.
+.. note::
+
+ Sometimes you want to make certain parts of your routes globally configurable.
+ Symfony2.1 provides you with a way to do this by leveraging service container
+ parameters. Read more about this in ":doc:`/cookbook/routing/service_container_parameters`.
+
Special Routing Parameters
~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1103,7 +1109,10 @@ a route+parameters back to a URL. The
system. Take the ``blog_show`` example route from earlier::
$params = $router->match('/blog/my-blog-post');
- // array('slug' => 'my-blog-post', '_controller' => 'AcmeBlogBundle:Blog:show')
+ // array(
+ // 'slug' => 'my-blog-post',
+ // '_controller' => 'AcmeBlogBundle:Blog:show',
+ // )
$uri = $router->generate('blog_show', array('slug' => 'my-blog-post'));
// /blog/my-blog-post
@@ -1116,9 +1125,12 @@ that route. With this information, any URL can easily be generated::
{
public function showAction($slug)
{
- // ...
+ // ...
- $url = $this->get('router')->generate('blog_show', array('slug' => 'my-blog-post'));
+ $url = $this->get('router')->generate(
+ 'blog_show',
+ array('slug' => 'my-blog-post')
+ );
}
}
@@ -1132,7 +1144,10 @@ In an upcoming section, you'll learn how to generate URLs from inside templates.
.. code-block:: javascript
- var url = Routing.generate('blog_show', { "slug": 'my-blog-post'});
+ var url = Routing.generate(
+ 'blog_show',
+ {"slug": 'my-blog-post'}
+ );
For more information, see the documentation for that bundle.
View
17 book/security.rst
@@ -434,17 +434,22 @@ Next, create the controller that will display the login form::
// get the login error if there is one
if ($request->attributes->has(SecurityContext::AUTHENTICATION_ERROR)) {
- $error = $request->attributes->get(SecurityContext::AUTHENTICATION_ERROR);
+ $error = $request->attributes->get(
+ SecurityContext::AUTHENTICATION_ERROR
+ );
} else {
$error = $session->get(SecurityContext::AUTHENTICATION_ERROR);
$session->remove(SecurityContext::AUTHENTICATION_ERROR);
}
- return $this->render('AcmeSecurityBundle:Security:login.html.twig', array(
- // last username entered by the user
- 'last_username' => $session->get(SecurityContext::LAST_USERNAME),
- 'error' => $error,
- ));
+ return $this->render(
+ 'AcmeSecurityBundle:Security:login.html.twig',
+ array(
+ // last username entered by the user
+ 'last_username' => $session->get(SecurityContext::LAST_USERNAME),
+ 'error' => $error,
+ )
+ );
}
}
View
26 book/service_container.rst
@@ -565,10 +565,14 @@ something like this::
Without using the service container, you can create a new ``NewsletterManager``
fairly easily from inside a controller::
+ use Acme\HelloBundle\Newsletter\NewsletterManager;
+
+ // ...
+
public function sendNewsletterAction()
{
$mailer = $this->get('my_mailer');
- $newsletter = new Acme\HelloBundle\Newsletter\NewsletterManager($mailer);
+ $newsletter = new NewsletterManager($mailer);
// ...
}
@@ -618,7 +622,10 @@ the service container gives you a much more appealing option:
use Symfony\Component\DependencyInjection\Reference;
// ...
- $container->setParameter('newsletter_manager.class', 'Acme\HelloBundle\Newsletter\NewsletterManager');
+ $container->setParameter(
+ 'newsletter_manager.class',
+ 'Acme\HelloBundle\Newsletter\NewsletterManager'
+ );
$container->setDefinition('my_mailer', ...);
$container->setDefinition('newsletter_manager', new Definition(
@@ -708,7 +715,10 @@ Injecting the dependency by the setter method just needs a change of syntax:
use Symfony\Component\DependencyInjection\Reference;
// ...
- $container->setParameter('newsletter_manager.class', 'Acme\HelloBundle\Newsletter\NewsletterManager');
+ $container->setParameter(
+ 'newsletter_manager.class',
+ 'Acme\HelloBundle\Newsletter\NewsletterManager'
+ );
$container->setDefinition('my_mailer', ...);
$container->setDefinition('newsletter_manager', new Definition(
@@ -767,12 +777,18 @@ it exists and do nothing if it doesn't:
use Symfony\Component\DependencyInjection\ContainerInterface;
// ...
- $container->setParameter('newsletter_manager.class', 'Acme\HelloBundle\Newsletter\NewsletterManager');
+ $container->setParameter(
+ 'newsletter_manager.class',
+ 'Acme\HelloBundle\Newsletter\NewsletterManager'
+ );
$container->setDefinition('my_mailer', ...);
$container->setDefinition('newsletter_manager', new Definition(
'%newsletter_manager.class%',
- array(new Reference('my_mailer', ContainerInterface::IGNORE_ON_INVALID_REFERENCE))
+ array(new Reference(
+ 'my_mailer',
+ ContainerInterface::IGNORE_ON_INVALID_REFERENCE
+ ))
));
In YAML, the special ``@?`` syntax tells the service container that the dependency
View
23 book/templating.rst
@@ -532,7 +532,9 @@ Including this template from any other template is simple:
<h1>Recent Articles<h1>
{% for article in articles %}
- {% include 'AcmeArticleBundle:Article:articleDetails.html.twig' with {'article': article} %}
+ {% include 'AcmeArticleBundle:Article:articleDetails.html.twig'
+ with {'article': article}
+ %}
{% endfor %}
{% endblock %}
@@ -582,10 +584,14 @@ articles::
{
public function recentArticlesAction($max = 3)
{
- // make a database call or other logic to get the "$max" most recent articles
+ // make a database call or other logic
+ // to get the "$max" most recent articles
$articles = ...;
- return $this->render('AcmeArticleBundle:Article:recentList.html.twig', array('articles' => $articles));
+ return $this->render(
+ 'AcmeArticleBundle:Article:recentList.html.twig',
+ array('articles' => $articles)
+ );
}
}
@@ -815,7 +821,11 @@ correctly:
.. code-block:: html+php
- <a href="<?php echo $view['router']->generate('_welcome', array(), true) ?>">Home</a>
+ <a href="<?php echo $view['router']->generate(
+ '_welcome',
+ array(),
+ true
+ ) ?>">Home</a>
.. index::
single: Templating; Linking to assets
@@ -1062,7 +1072,10 @@ customize the markup specifically for your application. By digging into the
// some logic to retrieve the blogs
$blogs = ...;
- $this->render('AcmeBlogBundle:Blog:index.html.twig', array('blogs' => $blogs));
+ $this->render(
+ 'AcmeBlogBundle:Blog:index.html.twig',
+ array('blogs' => $blogs)
+ );
}
When the ``AcmeBlogBundle:Blog:index.html.twig`` is rendered, Symfony2 actually
View
40 book/testing.rst
@@ -145,7 +145,10 @@ for its ``DemoController`` (`DemoControllerTest`_) that reads as follows::
$crawler = $client->request('GET', '/demo/hello/Fabien');
- $this->assertGreaterThan(0, $crawler->filter('html:contains("Hello Fabien")')->count());
+ $this->assertGreaterThan(
+ 0,
+ $crawler->filter('html:contains("Hello Fabien")')->count()
+ );
}
}
@@ -217,7 +220,10 @@ Or, test against the Response content directly if you just want to assert that
the content contains some text, or if the Response is not an XML/HTML
document::
- $this->assertRegExp('/Hello Fabien/', $client->getResponse()->getContent());
+ $this->assertRegExp(
+ '/Hello Fabien/',
+ $client->getResponse()->getContent()
+ );
.. _book-testing-request-method-sidebar:
@@ -260,14 +266,23 @@ document::
To get you started faster, here is a list of the most common and
useful test assertions::
- // Assert that there is at least one h2 tag with the class "subtitle"
- $this->assertGreaterThan(0, $crawler->filter('h2.subtitle')->count());
+ // Assert that there is at least one h2 tag
+ // with the class "subtitle"
+ $this->assertGreaterThan(
+ 0,
+ $crawler->filter('h2.subtitle')->count()
+ );
// Assert that there are exactly 4 h2 tags on the page
$this->assertCount(4, $crawler->filter('h2'));
// Assert that the "Content-Type" header is "application/json"
- $this->assertTrue($client->getResponse()->headers->contains('Content-Type', 'application/json'));
+ $this->assertTrue(
+ $client->getResponse()->headers->contains(
+ 'Content-Type',
+ 'application/json'
+ )
+ );
// Assert that the response content matches a regexp.
$this->assertRegExp('/foo/', $client->getResponse()->getContent());
@@ -277,10 +292,15 @@ document::
// Assert that the response status code is 404
$this->assertTrue($client->getResponse()->isNotFound());
// Assert a specific 200 status code
- $this->assertEquals(200, $client->getResponse()->getStatusCode());
+ $this->assertEquals(
+ 200,
+ $client->getResponse()->getStatusCode()
+ );
// Assert that the response is a redirect to /demo/contact
- $this->assertTrue($client->getResponse()->isRedirect('/demo/contact'));
+ $this->assertTrue(
+ $client->getResponse()->isRedirect('/demo/contact')
+ );
// or simply check that the response is a redirect to any URL
$this->assertTrue($client->getResponse()->isRedirect());
@@ -530,8 +550,10 @@ The Crawler can extract information from the nodes::
// Returns the node value for the first node
$crawler->text();
- // Extracts an array of attributes for all nodes (_text returns the node value)
- // returns an array for each element in crawler, each with the value and href
+ // Extracts an array of attributes for all nodes
+ // (_text returns the node value)
+ // returns an array for each element in crawler,
+ // each with the value and href
$info = $crawler->extract(array('_text', 'href'));
// Executes a lambda for each node and return an array of results
View
20 book/translation.rst
@@ -14,7 +14,8 @@ the user::
// text will *always* print out in English
echo 'Hello World';
- // text can be translated into the end-user's language or default to English
+ // text can be translated into the end-user's language or
+ // default to English
echo $translator->trans('Hello World');
.. note::
@@ -185,7 +186,10 @@ variable with a "placeholder"::
public function indexAction($name)
{
- $t = $this->get('translator')->trans('Hello %name%', array('%name%' => $name));
+ $t = $this->get('translator')->trans(
+ 'Hello %name%',
+ array('%name%' => $name)
+ );
new Response($t);
}
@@ -613,7 +617,15 @@ Message pluralization is a tough topic as the rules can be quite complex. For
instance, here is the mathematic representation of the Russian pluralization
rules::
- (($number % 10 == 1) && ($number % 100 != 11)) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2);
+ (($number % 10 == 1) && ($number % 100 != 11))
+ ? 0
+ : ((($number % 10 >= 2)
+ && ($number % 10 <= 4)
+ && (($number % 100 < 10)
+ || ($number % 100 >= 20)))
+ ? 1
+ : 2
+ );
As you can see, in Russian, you can have three different plural forms, each
given an index of 0, 1 or 2. For each form, the plural is different, and
@@ -982,7 +994,7 @@ steps:
.. _`i18n`: http://en.wikipedia.org/wiki/Internationalization_and_localization
.. _`L10n`: http://en.wikipedia.org/wiki/Internationalization_and_localization
.. _`strtr function`: http://www.php.net/manual/en/function.strtr.php
-.. _`ISO 31-11`: http://en.wikipedia.org/wiki/Interval_%28mathematics%29#The_ISO_notation
+.. _`ISO 31-11`: http://en.wikipedia.org/wiki/Interval_(mathematics)#Notations_for_intervals
.. _`Translatable Extension`: https://github.com/l3pp4rd/DoctrineExtensions
.. _`ISO3166 Alpha-2`: http://en.wikipedia.org/wiki/ISO_3166-1#Current_codes
.. _`ISO639-1`: http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
View
22 book/validation.rst
@@ -8,10 +8,10 @@ Validation is a very common task in web applications. Data entered in forms
needs to be validated. Data also needs to be validated before it is written
into a database or passed to a web service.
-Symfony2 ships with a `Validator`_ component that makes this task easy and
-transparent. This component is based on the
-`JSR303 Bean Validation specification`_. What? A Java specification in PHP?
-You heard right, but it's not as bad as it sounds. Let's look at how it
+Symfony2 ships with a `Validator`_ component that makes this task easy and
+transparent. This component is based on the
+`JSR303 Bean Validation specification`_. What? A Java specification in PHP?
+You heard right, but it's not as bad as it sounds. Let's look at how it
can be used in PHP.
.. index::
@@ -450,7 +450,10 @@ options can be specified in this way.
public static function loadValidatorMetadata(ClassMetadata $metadata)
{
- $metadata->addPropertyConstraint('gender', new Choice(array('male', 'female')));
+ $metadata->addPropertyConstraint(
+ 'gender',
+ new Choice(array('male', 'female'))
+ );
}
}
@@ -813,17 +816,20 @@ it looks like this::
$emailConstraint->message = 'Invalid email address';
// use the validator to validate the value
- $errorList = $this->get('validator')->validateValue($email, $emailConstraint);
+ $errorList = $this->get('validator')->validateValue(
+ $email,
+ $emailConstraint
+ );
if (count($errorList) == 0) {
// this IS a valid email address, do something
} else {
// this is *not* a valid email address
$errorMessage = $errorList[0]->getMessage()
-
+
// ... do something with the error
}
-
+
// ...
}
View
2  components/http_foundation/introduction.rst
@@ -450,7 +450,7 @@ class, which can make this even easier::
use Symfony\Component\HttpFoundation\JsonResponse;
$response = new JsonResponse();
- $response->setContent(array(
+ $response->setData(array(
'data' => 123
));
View
4 cookbook/assetic/asset_management.rst
@@ -64,14 +64,14 @@ drawn from various sources such as from within a bundle:
.. code-block:: html+jinja
- {% stylesheets '@AcmeFooBundle/Resources/public/css/*' %}
+ {% stylesheets 'bundles/acme_foo/css/*' %}
<link rel="stylesheet" href="{{ asset_url }}" />
{% endstylesheets %}
.. code-block:: html+php
<?php foreach ($view['assetic']->stylesheets(
- array('@AcmeFooBundle/Resources/public/css/*')
+ array('bundles/acme_foo/css/*')
) as $url): ?>
<link rel="stylesheet" href="<?php echo $view->escape($url) ?>" />
<?php endforeach; ?>
View
57 cookbook/console/console_command.rst
@@ -62,6 +62,26 @@ This command will now automatically be available to run:
$ app/console demo:greet Fabien
+Getting Services from the Service Container
+-------------------------------------------
+
+By using :class:`Symfony\\Bundle\\FrameworkBundle\\Command\\ContainerAwareCommand`
+as the base class for the command (instead of the more basic
+:class:`Symfony\\Component\\Console\\Command\\Command`), you have access to the
+service container. In other words, you have access to any configured service.
+For example, you could easily extend the task to be translatable::
+
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $name = $input->getArgument('name');
+ $translator = $this->getContainer()->get('translator');
+ if ($name) {
+ $output->writeln($translator->trans('Hello %name%!', array('%name%' => $name)));
+ } else {
+ $output->writeln($translator->trans('Hello!'));
+ }
+ }
+
Testing Commands
----------------
@@ -90,22 +110,31 @@ should be used instead of :class:`Symfony\\Component\\Console\\Application`::
}
}
-Getting Services from the Service Container
--------------------------------------------
+To be able to use the fully set up service container for your console tests
+you can extend your test from
+:class:`Symfony\Bundle\FrameworkBundle\Test\WebTestCase`::
-By using :class:`Symfony\\Bundle\\FrameworkBundle\\Command\\ContainerAwareCommand`
-as the base class for the command (instead of the more basic
-:class:`Symfony\\Component\\Console\\Command\\Command`), you have access to the
-service container. In other words, you have access to any configured service.
-For example, you could easily extend the task to be translatable::
+ use Symfony\Component\Console\Tester\CommandTester;
+ use Symfony\Bundle\FrameworkBundle\Console\Application;
+ use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
+ use Acme\DemoBundle\Command\GreetCommand;
- protected function execute(InputInterface $input, OutputInterface $output)
+ class ListCommandTest extends WebTestCase
{
- $name = $input->getArgument('name');
- $translator = $this->getContainer()->get('translator');
- if ($name) {
- $output->writeln($translator->trans('Hello %name%!', array('%name%' => $name)));
- } else {
- $output->writeln($translator->trans('Hello!'));
+ public function testExecute()
+ {
+ $kernel = $this->createKernel();
+ $kernel->boot();
+
+ $application = new Application($kernel);
+ $application->add(new GreetCommand());
+
+ $command = $application->find('demo:greet');
+ $commandTester = new CommandTester($command);
+ $commandTester->execute(array('command' => $command->getName()));
+
+ $this->assertRegExp('/.../', $commandTester->getDisplay());
+
+ // ...
}
}
View
6 cookbook/deployment-tools.rst
@@ -1,8 +1,8 @@
.. index::
single: Deployment
-Deploying a Symfony2 Application
-================================
+How to deploy a Symfony2 application
+====================================
.. note::
@@ -189,4 +189,4 @@ Platform as a Service Providers:
.. _`bundles that add deployment features`: http://knpbundles.com/search?q=deploy
.. _`Symfony IRC channel`: http://webchat.freenode.net/?channels=symfony
.. _`Memcached`: http://memcached.org/
-.. _`Redis`: http://redis.io/
+.. _`Redis`: http://redis.io/
View
34 cookbook/doctrine/file_uploads.rst
@@ -55,23 +55,29 @@ First, create a simple Doctrine Entity class to work with::
public function getAbsolutePath()
{
- return null === $this->path ? null : $this->getUploadRootDir().'/'.$this->path;
+ return null === $this->path
+ ? null
+ : $this->getUploadRootDir().'/'.$this->path;
}
public function getWebPath()
{
- return null === $this->path ? null : $this->getUploadDir().'/'.$this->path;
+ return null === $this->path
+ ? null
+ : $this->getUploadDir().'/'.$this->path;
}
protected function getUploadRootDir()
{
- // the absolute directory path where uploaded documents should be saved
+ // the absolute directory path where uploaded
+ // documents should be saved
return __DIR__.'/../../../../web/'.$this->getUploadDir();
}
protected function getUploadDir()
{
- // get rid of the __DIR__ so it doesn't screw when displaying uploaded doc/image in the view.
+ // get rid of the __DIR__ so it doesn't screw up
+ // when displaying uploaded doc/image in the view.
return 'uploads/documents';
}
}
@@ -213,8 +219,12 @@ object, which is what's returned after a ``file`` field is submitted::
// use the original file name here but you should
// sanitize it at least to avoid any security issues
- // move takes the target directory and then the target filename to move to
- $this->file->move($this->getUploadRootDir(), $this->file->getClientOriginalName());
+ // move takes the target directory and then the
+ // target filename to move to
+ $this->file->move(
+ $this->getUploadRootDir(),
+ $this->file->getClientOriginalName()
+ );
// set the path property to the filename where you've saved the file
$this->path = $this->file->getClientOriginalName();
@@ -266,7 +276,8 @@ Next, refactor the ``Document`` class to take advantage of these callbacks::
{
if (null !== $this->file) {
// do whatever you want to generate a unique name
- $this->path = sha1(uniqid(mt_rand(), true)).'.'.$this->file->guessExtension();
+ $filename = sha1(uniqid(mt_rand(), true));
+ $this->path = $filename.'.'.$this->file->guessExtension();
}
}
@@ -373,7 +384,10 @@ property, instead of the actual filename::
// you must throw an exception here if the file cannot be moved
// so that the entity is not persisted to the database
// which the UploadedFile move() method does
- $this->file->move($this->getUploadRootDir(), $this->id.'.'.$this->file->guessExtension());
+ $this->file->move(
+ $this->getUploadRootDir(),
+ $this->id.'.'.$this->file->guessExtension()
+ );
unset($this->file);
}
@@ -398,7 +412,9 @@ property, instead of the actual filename::
public function getAbsolutePath()
{
- return null === $this->path ? null : $this->getUploadRootDir().'/'.$this->id.'.'.$this->path;
+ return null === $this->path
+ ? null
+ : $this->getUploadRootDir().'/'.$this->id.'.'.$this->path;
}
}
View
19 cookbook/doctrine/multiple_entity_managers.rst
@@ -64,7 +64,7 @@ two connections, one for each entity manager.
.. note::
- When working with multiple connections and entity managers, you should be
+ When working with multiple connections and entity managers, you should be
explicit about which configuration you want. If you *do* omit the name of
the connection or entity manager, the default (i.e. ``default``) is used.
@@ -98,7 +98,7 @@ the default entity manager (i.e. ``default``) is returned::
// both return the "default" em
$em = $this->get('doctrine')->getManager();
$em = $this->get('doctrine')->getManager('default');
-
+
$customerEm = $this->get('doctrine')->getManager('customer');
}
}
@@ -115,17 +115,20 @@ The same applies to repository call::
{
// Retrieves a repository managed by the "default" em
$products = $this->get('doctrine')
- ->getRepository('AcmeStoreBundle:Product')
- ->findAll();
+ ->getRepository('AcmeStoreBundle:Product')
+ ->findAll()
+ ;
// Explicit way to deal with the "default" em
$products = $this->get('doctrine')
- ->getRepository('AcmeStoreBundle:Product', 'default')
- ->findAll();
+ ->getRepository('AcmeStoreBundle:Product', 'default')
+ ->findAll()
+ ;
// Retrieves a repository managed by the "customer" em
$customers = $this->get('doctrine')
- ->getRepository('AcmeCustomerBundle:Customer', 'customer')
- ->findAll();
+ ->getRepository('AcmeCustomerBundle:Customer', 'customer')
+ ->findAll()
+ ;
}
}
View
23 cookbook/doctrine/registration_form.rst
@@ -194,7 +194,11 @@ Next, create the form for this ``Registration`` model::
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('user', new UserType());
- $builder->add('terms', 'checkbox', array('property_path' => 'termsAccepted'));
+ $builder->add(
+ 'terms',
+ 'checkbox',
+ array('property_path' => 'termsAccepted')
+ );
}
public function getName()
@@ -227,9 +231,15 @@ controller for displaying the registration form::
{
public function registerAction()
{
- $form = $this->createForm(new RegistrationType(), new Registration());
-
- return $this->render('AcmeAccountBundle:Account:register.html.twig', array('form' => $form->createView()));
+ $form = $this->createForm(
+ new RegistrationType(),
+ new Registration()
+ );
+
+ return $this->render(
+ 'AcmeAccountBundle:Account:register.html.twig',
+ array('form' => $form->createView())
+ );
}
}
@@ -264,7 +274,10 @@ the validation and saves the data into the database::
return $this->redirect(...);
}
- return $this->render('AcmeAccountBundle:Account:register.html.twig', array('form' => $form->createView()));
+ return $this->render(
+ 'AcmeAccountBundle:Account:register.html.twig',
+ array('form' => $form->createView())
+ );
}
That's it! Your form now validates, and allows you to save the ``User``
View
13 cookbook/email/dev_environment.rst
@@ -96,7 +96,12 @@ Now, suppose you're sending an email to ``recipient@example.com``.
->setSubject('Hello Email')
->setFrom('send@example.com')
->setTo('recipient@example.com')
- ->setBody($this->renderView('HelloBundle:Hello:email.txt.twig', array('name' => $name)))
+ ->setBody(
+ $this->renderView(
+ 'HelloBundle:Hello:email.txt.twig',
+ array('name' => $name)
+ )
+ )
;
$this->get('mailer')->send($message);
@@ -150,10 +155,10 @@ you to open the report with details of the sent emails.
<!-- app/config/config_dev.xml -->
- <!--
+ <!--
xmlns:webprofiler="http://symfony.com/schema/dic/webprofiler"
- xsi:schemaLocation="http://symfony.com/schema/dic/webprofiler
- http://symfony.com/schema/dic/webprofiler/webprofiler-1.0.xsd">
+ xsi:schemaLocation="http://symfony.com/schema/dic/webprofiler
+ http://symfony.com/schema/dic/webprofiler/webprofiler-1.0.xsd">
-->
<webprofiler:config
View
7 cookbook/email/email.rst
@@ -106,7 +106,12 @@ an email is pretty straightforward::
->setSubject('Hello Email')
->setFrom('send@example.com')
->setTo('recipient@example.com')
- ->setBody($this->renderView('HelloBundle:Hello:email.txt.twig', array('name' => $name)))
+ ->setBody(
+ $this->renderView(
+ 'HelloBundle:Hello:email.txt.twig',
+ array('name' => $name)
+ )
+ )
;
$this->get('mailer')->send($message);
View
16 cookbook/form/dynamic_form_generation.rst
@@ -91,10 +91,10 @@ might look like the following::
// src/Acme/DemoBundle/Form/EventListener/AddNameFieldSubscriber.php
namespace Acme\DemoBundle\Form\EventListener;
- use Symfony\Component\Form\Event\DataEvent;
+ use Symfony\Component\Form\FormEvent;
+ use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
- use Symfony\Component\Form\FormEvents;
class AddNameFieldSubscriber implements EventSubscriberInterface
{
@@ -145,20 +145,16 @@ The ``FormEvents::PRE_SET_DATA`` line actually resolves to the string ``form.pre
The `FormEvents class`_ serves an organizational purpose. It is a centralized location
in which you can find all of the various form events available.
-While this example could have used the ``form.set_data`` event or even the ``form.post_set_data``
-events just as effectively, by using ``form.pre_set_data`` you guarantee that
+While this example could have used the ``form.post_set_data``
+event just as effectively, by using ``form.pre_set_data`` you guarantee that
the data being retrieved from the ``Event`` object has in no way been modified
-by any other subscribers or listeners. This is because ``form.pre_set_data``
-passes a `DataEvent`_ object instead of the `FilterDataEvent`_ object passed
-by the ``form.set_data`` event. `DataEvent`_, unlike its child `FilterDataEvent`_,
-lacks a setData() method.
+by any other subscribers or listeners because ``form.pre_set_data`` is the
+first form event dispatched.
.. note::
You may view the full list of form events via the `FormEvents class`_,
found in the form bundle.
-.. _`DataEvent`: https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Form/Event/DataEvent.php
.. _`FormEvents class`: https://github.com/symfony/Form/blob/master/FormEvents.php
.. _`Form class`: https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Form/Form.php
-.. _`FilterDataEvent`: https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Form/Event/FilterDataEvent.php
View
6 cookbook/form/form_collections.rst
@@ -321,7 +321,7 @@ new "tag" forms. To render it, make the following change to your template:
.. code-block:: html+php
- <ul class="tags" data-prototype="<?php echo $view->escape($view['form']->row($form['tags']->getVar('prototype'))) ?>">
+ <ul class="tags" data-prototype="<?php echo $view->escape($view['form']->row($form['tags']->vars['prototype'])) ?>">
...
</ul>
@@ -607,7 +607,9 @@ the relationship between the removed ``Tag`` and ``Task`` object.
$originalTags = array();
// Create an array of the current Tag objects in the database
- foreach ($task->getTags() as $tag) $originalTags[] = $tag;
+ foreach ($task->getTags() as $tag) {
+ $originalTags[] = $tag;
+ }
$editForm = $this->createForm(new TaskType(), $task);
View
27 cookbook/map.rst.inc
@@ -24,7 +24,7 @@
* :doc:`/cookbook/configuration/pdo_session_storage`
* :doc:`/cookbook/configuration/apache_router`
-* **Console Commands**
+* :doc:`/cookbook/console/index`
* :doc:`/cookbook/console/console_command`
* :doc:`/cookbook/console/usage`
@@ -39,6 +39,10 @@
* :doc:`/cookbook/debugging`
+* **Deployment**
+
+* :doc:`/cookbook/deployment-tools`
+
* :doc:`/cookbook/doctrine/index`
* :doc:`/cookbook/doctrine/file_uploads`
@@ -99,16 +103,6 @@
* :doc:`/cookbook/routing/method_parameters`
* :doc:`/cookbook/routing/service_container_parameters`
-* **symfony1**
-
- * :doc:`/cookbook/symfony1`
-
-* :doc:`/cookbook/service_container/index`
-
- * :doc:`/cookbook/service_container/event_listener`
- * :doc:`/cookbook/service_container/scopes`
- * :doc:`/cookbook/service_container/compiler_passes`
-
* :doc:`/cookbook/security/index`
* :doc:`/cookbook/security/entity_provider`
@@ -123,6 +117,16 @@
* :doc:`/cookbook/security/custom_authentication_provider`
* :doc:`/cookbook/security/target_path`
+* :doc:`/cookbook/service_container/index`
+
+ * :doc:`/cookbook/service_container/event_listener`
+ * :doc:`/cookbook/service_container/scopes`
+ * :doc:`/cookbook/service_container/compiler_passes`
+
+* **symfony1**
+
+ * :doc:`/cookbook/symfony1`
+
* :doc:`/cookbook/templating/index`
* :doc:`/cookbook/templating/global_variables`
@@ -150,4 +154,3 @@
* :doc:`/cookbook/workflow/new_project_git`
* :doc:`/cookbook/workflow/new_project_svn`
-* :doc:`/cookbook/deployment-tools`
View
2  cookbook/security/acl.rst
@@ -105,7 +105,7 @@ Creating an ACL, and adding an ACE
// ... setup $form, and bind data
if ($form->isValid()) {
- $entityManager = $this->get('doctrine.orm.default_entity_manager');
+ $entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($comment);
$entityManager->flush();
View
5 cookbook/testing/doctrine.rst
@@ -39,7 +39,10 @@ which makes all of this quite easy::
{
static::$kernel = static::createKernel();
static::$kernel->boot();
- $this->em = static::$kernel->getContainer()->get('doctrine')->getManager();
+ $this->em = static::$kernel->getContainer()
+ ->get('doctrine')
+ ->getManager()
+ ;
}
public function testSearchByCategoryName()
View
15 cookbook/testing/profiling.rst
@@ -31,10 +31,16 @@ the ``test`` environment)::
// Check that the profiler is enabled
if ($profile = $client->getProfile()) {
// check the number of requests
- $this->assertLessThan(10, $profile->getCollector('db')->getQueryCount());
+ $this->assertLessThan(
+ 10,
+ $profile->getCollector('db')->getQueryCount()
+ );
// check the time spent in the framework
- $this->assertLessThan(500, $profile->getCollector('time')->getTotalTime());
+ $this->assertLessThan(
+ 500,
+ $profile->getCollector('time')->getTotalTime()
+ );
}
}
}
@@ -46,7 +52,10 @@ finish. It's easy to achieve if you embed the token in the error message::
$this->assertLessThan(
30,
$profile->get('db')->getQueryCount(),
- sprintf('Checks that query count is less than 30 (token %s)', $profile->getToken())
+ sprintf(
+ 'Checks that query count is less than 30 (token %s)',
+ $profile->getToken()
+ )
);
.. caution::
View
2  reference/forms/types/collection.rst
@@ -300,7 +300,7 @@ collection field:
.. code-block:: php
- <?php echo $view['form']->row($form['emails']->getVar('prototype')) ?>
+ <?php echo $view['form']->row($form['emails']->vars['prototype']) ?>
Note that all you really need is the "widget", but depending on how you're
rendering your form, having the entire "form row" may be easier for you.
View
4 reference/forms/types/form.rst
@@ -19,8 +19,10 @@ on all fields.
.. include:: /reference/forms/types/options/trim.rst.inc
+.. include:: /reference/forms/types/options/mapped.rst.inc
+
.. include:: /reference/forms/types/options/property_path.rst.inc
.. include:: /reference/forms/types/options/attr.rst.inc
-.. include:: /reference/forms/types/options/translation_domain.rst.inc
+.. include:: /reference/forms/types/options/translation_domain.rst.inc
View
7 reference/forms/types/options/mapped.rst.inc
@@ -0,0 +1,7 @@
+mapped
+~~~~~~
+
+**type**: ``boolean``
+
+If you wish the field to be ignored when reading or writing to the object, you
+can set the ``mapped`` option to ``false``
View
7 reference/forms/types/options/property_path.rst.inc
@@ -11,4 +11,9 @@ you can set the ``property_path`` option. Its default value is the field's
name.
If you wish the field to be ignored when reading or writing to the object
-you can set the ``property_path`` option to ``false``
+you can set the ``property_path`` option to ``false``, but using
+``property_path`` for this purpose is deprecated, you should do it the way
+described below:
+
+.. versionadded:: 2.1
+ Since 2.1, the ``mapped`` option has been added for this use-case.
Please sign in to comment.
Something went wrong with that request. Please try again.