8000 Command lazy loading · symfony/symfony-docs@811772e · GitHub
[go: up one dir, main page]

Skip to content

Commit 811772e

Browse files
committed
Command lazy loading
1 parent 7bb20ba commit 811772e

File tree

2 files changed

+151
-3
lines changed

2 files changed

+151
-3
lines changed

console/commands_as_services.rst

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,73 @@ works! You can call the ``app:sunshine`` command and start logging.
6666

6767
.. caution::
6868

69-
You *do* have access to services in ``configure()``. However, try to avoid doing
70-
any work (e.g. making database queries), as that code will be run, even if you're
71-
using the console to execute a different command.
69+
You *do* have access to services in ``configure()``. However, if your command is
70+
not :ref:`lazy <console-command-service-lazy-loading>`, try to avoid doing any
71+
work (e.g. making database queries), as that code will be run, even if you're using
72+
the console to execute a different command.
73+
74+
.. _console-command-service-lazy-loading:
75+
76+
Lazy Loading
77+
------------
78+
79+
.. versionadded:: 3.4
80+
Support for command lazy loading was introduced in Symfony 3.4.
81+
82+
To make your command lazily loaded, either define its ``$defaultName`` static property::
83+
84+
class SunshineCommand extends Command
85+
{
86+
protected static $defaultName = 'app:sunshine';
87+
88+
// ...
89+
}
90+
91+
Or set the ``command`` attribute on the ``console.command`` tag in your service definition::
92+
93+
.. configuration-block::
94+
95+
.. code-block:: yaml
96+
97+
services:
98+
99+
AppBundle\Command\SunshineCommand:
100+
tags:
101+
- { name: 'console.command', command: 'app:sunshine' }
102+
# ...
103+
104+
.. code-block:: xml
105+
106+
<?xml version="1.0" encoding="UTF-8" ?>
107+
<container xmlns="http://symfony.com/schema/dic/services"
108+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
109+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
110+
111+
<services>
112+
113+
<service id="AppBundle\Command\SunshineCommand">
114+
<tag name="console.command" command="app:sunshine" />
115+
</service>
116+
117+
</services>
118+
</container>
119+
120+
.. code-block:: php
121+
122+
use AppBundle\Command\SunshineCommand;
123+
124+
//...
125+
126+
$container
127+
->register(SunshineCommand::class)
128+
->addTag('console.command', array('command' => 'app:sunshine'))
129+
;
130+
131+
That's it. In one way or another, the ``SunshineCommand`` will be instantiated only when
132+
actually calling the ``app:sunshine`` command.
133+
134+
.. note::
135+
You don't need to call ``setName()`` for configuring the command when it is lazy.
136+
137+
.. caution::
138+
Calling the ``list`` command requires to load all commands, lazy ones included.

console/lazy_commands.rst

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
How to Make Commands Lazily Loaded
2+
==================================
3+
4+
.. versionadded:: 3.4
5+
Support for command lazy loading was introduced in Symfony 3.4.
6+
7+
.. note::
8+
If you are using the Symfony full-stack framework, you are probably looking for
9+
:ref:`lazy loading of commands defined as services <console-command-service-lazy-loading>`
10+
11+
The traditional way of adding commands to your application is to use
12+
:method:`Symfony\\Component\\Console\\Application::add` which expects a
13+
``Command`` instance as argument.
14+
In order to get commands loaded lazily, you need to register an intermediate router
15+
which will be responsible for returning ``Command`` instances::
16+
17+
use AppBundle\Command\HeavyCommand;
18+
use Symfony\Component\Console\Application;
19+
use Symfony\Component\Console\CommandLoader\FactoryCommmandLoader;
20+
21+
$commandLoader = new FactoryCommandLoader(array(
22+
'app:heavy' => function () { return new HeavyCommand() },
23+
));
24+
25+
$application = new Application();
26+
$application->setCommandLoader($commandLoader);
27+
$application->run();
28+
29+
This way, the ``HeavyCommand`` instance will be created only when the ``app:foo``
30+
command is actually called.
31+
32+
This example makes use of the built-in
33+
:class:`Symfony\\Component\\Console\\CommandLoader\\FactoryCommandLoader` class,
34+
but the :method:`Symfony\\Component\\Console\\Application::setCommandLoader`
35+
method accepts any
36+
:class:`Symfony\\Component\\Console\\CommandLoader\\CommandLoaderInterface`
37+
instance so you can easily create and use your own implementation.
38+
39+
Built-in Command Loaders
40+
------------------------
41+
42+
``FactoryCommandLoader``
43+
~~~~~~~~~~~~~~~~~~~~~~~~
44+
45+
The :class:`Symfony\\Component\\Console\\CommandLoader\\FactoryCommandLoader`
46+
class provides a simple way of getting commands lazily loaded as it takes an
47+
array of ``Command`` factories as only constructor argument::
48+
49+
use Symfony\Component\Console\CommandLoader\FactoryCommandLoader;
50+
51+
$commandLoader = new FactoryCommandLoader(array(
52+
'app:foo' => function () { return new FooCommand() },
53+
'app:bar' => array(BarCommand::class, 'create'),
54+
));
55+
56+
Factories can be any PHP callable and will be executed each time
57+
:method:`Symfony\\Component\\Console\\CommandLoader\\FactoryCommandLoader::get`
58+
is called.
59+
60+
``ContainerCommandLoader``
61+
~~~~~~~~~~~~~~~~~~~~~~~~~~
62+
63+
The :class:`Symfony\\Component\\Console\\CommandLoader\\ContainerCommandLoader`
64+
class can be used to load commands from a PSR-11 container.
65+
As such, its constructor takes a PSR-11 ``ContainerInterface`` implementation as
66+
first argument and a command map as last argument. The command map must be an array
67+
with command names as keys and service identifiers as values::
68+
69+
use Symfony\Component\Console\CommandLoader\ContainerCommandLoader;
70+
use Symfony\Component\DependencyInjection\ContainerBuilder;
71+
72+
$container = new ContainerBuilder();
73+
$container->register(FooCommand::class, FooCommand::class);
74+
$container->compile();
75+
76+
$commandLoader = new ContainerCommandLoader($container, array(
77+
'app:foo' => FooCommand::class,
78+
));
79+
80+
Like this, executing the `app:foo` command will load the ``FooCommand`` service
81+
by calling ``$container->get(FooCommand::class)``.

0 commit comments

Comments
 (0)
0