Skip to content

Commit a3710e1

Browse files
committed
Merge branch '2.1'
Conflicts: cookbook/security/form_login.rst
2 parents b254e35 + 6cf091d commit a3710e1

File tree

9 files changed

+290
-110
lines changed

9 files changed

+290
-110
lines changed

contributing/documentation/format.rst

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ and to the PHP documentation:
157157
158158
:phpclass:`SimpleXMLElement`
159159
160-
`DateTime::createFromFormat`_
160+
:phpmethod:`DateTime::createFromFormat`
161161
162162
:phpfunction:`iterator_to_array`
163163
@@ -215,4 +215,3 @@ Installing the Sphinx extensions
215215
.. _Pygments website: http://pygments.org/languages/
216216
.. _source: https://github.com/fabpot/sphinx-php
217217
.. _Sphinx quick setup: http://sphinx-doc.org/tutorial.html#setting-up-the-documentation-sources
218-
.. _`DateTime::createFromFormat`: http://php.net/manual/en/datetime.createfromformat.php

cookbook/console/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ Console
77
console_command
88
usage
99
sending_emails
10+
logging

cookbook/console/logging.rst

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
.. index::
2+
single: Console; Enabling logging
3+
4+
How to enable logging in Console Commands
5+
=========================================
6+
7+
The Console component doesn't provide any logging capabilities out of the box.
8+
Normally, you run console commands manually and observe the output, which is
9+
why logging is not provided. However, there are cases when you might need
10+
logging. For example, if you are running console commands unattended, such
11+
as from cron jobs or deployment scripts, it may be easier to use Symfony's
12+
logging capabilities instead of configuring other tools to gather console
13+
output and process it. This can be especially handful if you already have
14+
some existing setup for aggregating and analyzing Symfony logs.
15+
16+
There are basically two logging cases you would need:
17+
* Manually logging some information from your command;
18+
* Logging uncaught Exceptions.
19+
20+
Manually logging from a console Command
21+
---------------------------------------
22+
23+
This one is really simple. When you create a console command within the full
24+
framework as described in ":doc:`/cookbook/console/console_command`", your command
25+
extends :class:`Symfony\\Bundle\\FrameworkBundle\\Command\\ContainerAwareCommand`.
26+
This means that you can simply access the standard logger service through the
27+
container and use it to do the logging::
28+
29+
// src/Acme/DemoBundle/Command/GreetCommand.php
30+
namespace Acme\DemoBundle\Command;
31+
32+
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
33+
use Symfony\Component\Console\Input\InputArgument;
34+
use Symfony\Component\Console\Input\InputInterface;
35+
use Symfony\Component\Console\Input\InputOption;
36+
use Symfony\Component\Console\Output\OutputInterface;
37+
use Symfony\Component\HttpKernel\Log\LoggerInterface;
38+
39+
class GreetCommand extends ContainerAwareCommand
40+
{
41+
// ...
42+
43+
protected function execute(InputInterface $input, OutputInterface $output)
44+
{
45+
/** @var $logger LoggerInterface */
46+
$logger = $this->getContainer()->get('logger');
47+
48+
$name = $input->getArgument('name');
49+
if ($name) {
50+
$text = 'Hello '.$name;
51+
} else {
52+
$text = 'Hello';
53+
}
54+
55+
if ($input->getOption('yell')) {
56+
$text = strtoupper($text);
57+
$logger->warn('Yelled: '.$text);
58+
}
59+
else {
60+
$logger->info('Greeted: '.$text);
61+
}
62+
63+
$output->writeln($text);
64+
}
65+
}
66+
67+
Depending on the environment in which you run your command (and your logging
68+
setup), you should see the logged entries in ``app/logs/dev.log`` or ``app/logs/prod.log``.
69+
70+
Enabling automatic Exceptions logging
71+
-------------------------------------
72+
73+
To get your console application to automatically log uncaught exceptions
74+
for all of your commands, you'll need to do a little bit more work.
75+
76+
First, create a new sub-class of :class:`Symfony\\Bundle\\FrameworkBundle\\Console\\Application`
77+
and override its :method:`Symfony\\Bundle\\FrameworkBundle\\Console\\Application::run`
78+
method, where exception handling should happen:
79+
80+
.. warning::
81+
82+
Due to the nature of the core :class:`Symfony\\Component\\Console\\Application`
83+
class, much of the :method:`run<Symfony\\Bundle\\FrameworkBundle\\Console\\Application::run>`
84+
method has to be duplicated and even a private property ``originalAutoExit``
85+
re-implemented. This serves as an example of what you *could* do in your
86+
code, though there is a high risk that something may break when upgrading
87+
to future versions of Symfony.
88+
89+
90+
.. code-block:: php
91+
92+
// src/Acme/DemoBundle/Console/Application.php
93+
namespace Acme\DemoBundle\Console;
94+
95+
use Symfony\Bundle\FrameworkBundle\Console\Application as BaseApplication;
96+
use Symfony\Component\Console\Input\InputInterface;
97+
use Symfony\Component\Console\Output\OutputInterface;
98+
use Symfony\Component\Console\Output\ConsoleOutputInterface;
99+
use Symfony\Component\HttpKernel\Log\LoggerInterface;
100+
use Symfony\Component\HttpKernel\KernelInterface;
101+
use Symfony\Component\Console\Output\ConsoleOutput;
102+
use Symfony\Component\Console\Input\ArgvInput;
103+
104+
class Application extends BaseApplication
105+
{
106+
private $originalAutoExit;
107+
108+
public function __construct(KernelInterface $kernel)
109+
{
110+
parent::__construct($kernel);
111+
$this->originalAutoExit = true;
112+
}
113+
114+
/**
115+
* Runs the current application.
116+
*
117+
* @param InputInterface $input An Input instance
118+
* @param OutputInterface $output An Output instance
119+
*
120+
* @return integer 0 if everything went fine, or an error code
121+
*
122+
* @throws \Exception When doRun returns Exception
123+
*
124+
* @api
125+
*/
126+
public function run(InputInterface $input = null, OutputInterface $output = null)
127+
{
128+
// make the parent method throw exceptions, so you can log it
129+
$this->setCatchExceptions(false);
130+
131+
if (null === $input) {
132+
$input = new ArgvInput();
133+
}
134+
135+
if (null === $output) {
136+
$output = new ConsoleOutput();
137+
}
138+
139+
try {
140+
$statusCode = parent::run($input, $output);
141+
} catch (\Exception $e) {
142+
143+
/** @var $logger LoggerInterface */
144+
$logger = $this->getKernel()->getContainer()->get('logger');
145+
146+
$message = sprintf(
147+
'%s: %s (uncaught exception) at %s line %s while running console command `%s`',
148+
get_class($e),
149+
$e->getMessage(),
150+
$e->getFile(),
151+
$e->getLine(),
152+
$this->getCommandName($input)
153+
);
154+
$logger->crit($message);
155+
156+
if ($output instanceof ConsoleOutputInterface) {
157+
$this->renderException($e, $output->getErrorOutput());
158+
} else {
159+
$this->renderException($e, $output);
160+
}
161+
$statusCode = $e->getCode();
162+
163+
$statusCode = is_numeric($statusCode) && $statusCode ? $statusCode : 1;
164+
}
165+
166+
if ($this->originalAutoExit) {
167+
if ($statusCode > 255) {
168+
$statusCode = 255;
169+
}
170+
// @codeCoverageIgnoreStart
171+
exit($statusCode);
172+
// @codeCoverageIgnoreEnd
173+
}
174+
175+
return $statusCode;
176+
}
177+
178+
public function setAutoExit($bool)
179+
{
180+
// parent property is private, so we need to intercept it in a setter
181+
$this->originalAutoExit = (Boolean) $bool;
182+
parent::setAutoExit($bool);
183+
}
184+
185+
}
186+
187+
In the code above, you disable exception catching so the parent ``run`` method
188+
will throw all exceptions. When an exception is caught, you simple log it by
189+
accessing the ``logger`` service from the service container and then handle
190+
the rest of the logic in the same way that the parent ``run`` method does
191+
(specifically, since the parent :method:`run<Symfony\\Bundle\\FrameworkBundle\\Console\\Application::run>`
192+
method will not handle exceptions rendering and status code handling when
193+
``catchExceptions`` is set to false, it has to be done in the overridden
194+
method).
195+
196+
For the extended Application class to work properly with in console shell mode,
197+
you have to do a small trick to intercept the ``autoExit`` setter and store the
198+
setting in a different property, since the parent property is private.
199+
200+
Now to be able to use your extended ``Application`` class you need to adjust
201+
the ``app/console`` script to use the new class instead of the default::
202+
203+
// app/console
204+
205+
// ...
206+
// replace the following line:
207+
// use Symfony\Bundle\FrameworkBundle\Console\Application;
208+
use Acme\DemoBundle\Console\Application;
209+
210+
// ...
211+
212+
That's it! Thanks to autoloader, your class will now be used instead of original
213+
one.
214+
215+
Logging non-0 exit statuses
216+
---------------------------
217+
218+
The logging capabilities of the console can be further extended by logging
219+
non-0 exit statuses. This way you will know if a command had any errors, even
220+
if no exceptions were thrown.
221+
222+
In order to do that, you'd have to modify the ``run()`` method of your extended
223+
``Application`` class in the following way::
224+
225+
public function run(InputInterface $input = null, OutputInterface $output = null)
226+
{
227+
// make the parent method throw exceptions, so you can log it
228+
$this->setCatchExceptions(false);
229+
230+
// store the autoExit value before resetting it - you'll need it later
231+
$autoExit = $this->originalAutoExit;
232+
$this->setAutoExit(false);
233+
234+
// ...
235+
236+
if ($autoExit) {
237+
if ($statusCode > 255) {
238+
$statusCode = 255;
239+
}
240+
241+
// log non-0 exit codes along with command name
242+
if ($statusCode !== 0) {
243+
/** @var $logger LoggerInterface */
244+
$logger = $this->getKernel()->getContainer()->get('logger');
245+
$logger->warn(sprintf('Command `%s` exited with status code %d', $this->getCommandName($input), $statusCode));
246+
}
247+
248+
// @codeCoverageIgnoreStart
249+
exit($statusCode);
250+
// @codeCoverageIgnoreEnd
251+
}
252+
253+
return $statusCode;
254+
}

cookbook/map.rst.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
* :doc:`/cookbook/console/console_command`
3030
* :doc:`/cookbook/console/usage`
3131
* :doc:`/cookbook/console/sending_emails`
32+
* :doc:`/cookbook/console/logging`
3233

3334
* :doc:`/cookbook/controller/index`
3435

cookbook/security/form_login.rst

Lines changed: 3 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -12,95 +12,9 @@ configuration is shown in the next section.
1212
Form Login Configuration Reference
1313
----------------------------------
1414

15-
.. configuration-block::
16-
17-
.. code-block:: yaml
18-
19-
# app/config/security.yml
20-
security:
21-
firewalls:
22-
main:
23-
form_login:
24-
# the user is redirected here when he/she needs to login
25-
login_path: /login
26-
27-
# if true, forward the user to the login form instead of redirecting
28-
use_forward: false
29-
30-
# submit the login form here
31-
check_path: /login_check
32-
33-
# by default, the login form *must* be a POST, not a GET
34-
post_only: true
35-
36-
# login success redirecting options (read further below)
37-
always_use_default_target_path: false
38-
default_target_path: /
39-
target_path_parameter: _target_path
40-
use_referer: false
41-
42-
# login failure redirecting options (read further below)
43-
failure_path: null
44-
failure_forward: false
45-
failure_path_parameter: _failure_path
46-
47-
# field names for the username and password fields
48-
username_parameter: _username
49-
password_parameter: _password
50-
51-
# csrf token options
52-
csrf_parameter: _csrf_token
53-
intention: authenticate
54-
55-
.. code-block:: xml
56-
57-
<!-- app/config/security.xml -->
58-
<config>
59-
<firewall>
60-
<form-login
61-
check_path="/login_check"
62-
login_path="/login"
63-
use_forward="false"
64-
always_use_default_target_path="false"
65-
default_target_path="/"
66-
target_path_parameter="_target_path"
67-
use_referer="false"
68-
failure_path="null"
69-
failure_forward="false"
70-
failure_path_parameter="_failure_path"
71-
username_parameter="_username"
72-
password_parameter="_password"
73-
csrf_parameter="_csrf_token"
74-
intention="authenticate"
75-
post_only="true"
76-
/>
77-
</firewall>
78-
</config>
79-
80-
.. code-block:: php
81-
82-
// app/config/security.php
83-
$container->loadFromExtension('security', array(
84-
'firewalls' => array(
85-
'main' => array('form_login' => array(
86-
'check_path' => '/login_check',
87-
'login_path' => '/login',
88-
'user_forward' => false,
89-
'always_use_default_target_path' => false,
90-
'default_target_path' => '/',
91-
'target_path_parameter' => _target_path,
92-
'use_referer' => false,
93-
'failure_path' => null,
94-
'failure_forward' => false,
95-
'failure_path_parameter' => _failure_path,
96-
'username_parameter' => '_username',
97-
'password_parameter' => '_password',
98-
'csrf_parameter' => '_csrf_token',
99-
'intention' => 'authenticate',
100-
'post_only' => true,
101-
)),
102-
),
103-
));
15+
To see the full form login configuration reference, see
16+
:doc:`/reference/configuration/security`. Some of the more interesting options
17+
are explained below.
10418

10519
Redirecting after Success
10620
-------------------------

0 commit comments

Comments
 (0)