Skip to content

Commit dd1dd63

Browse files
[Console] Add LazyCommandTrait to help writing lazy commands
1 parent d71aa52 commit dd1dd63

File tree

1 file changed

+102
-0
lines changed

1 file changed

+102
-0
lines changed
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Console\Command;
13+
14+
use Psr\Container\ContainerInterface;
15+
use Symfony\Component\Console\Input\InputInterface;
16+
use Symfony\Component\Console\Output\OutputInterface;
17+
use Symfony\Contracts\Service\ServiceSubscriberInterface;
18+
19+
/**
20+
* @method int exec(InputInterface $input, OutputInterface $output, ...$services) Extra arguments declared after $input and $output will be autowired
21+
*
22+
* @author Nicolas Grekas <p@tchwork.com>
23+
*/
24+
trait LazyCommandTrait
25+
{
26+
private $container;
27+
28+
/**
29+
* @required
30+
*/
31+
public function setContainer(ContainerInterface $container): void
32+
{
33+
$this->container = $container;
34+
35+
if (\is_callable(['parent', __FUNCTION__])) {
36+
parent::setContainer($container);
37+
}
38+
}
39+
40+
protected function execute(InputInterface $input, OutputInterface $output): int
41+
{
42+
if (!$this instanceof ServiceSubscriberInterface) {
43+
throw new \LogicException(sprintf('Class "%s" should declare that it implements "%s".', self::class, ServiceSubscriberInterface::class));
44+
}
45+
46+
$arguments = [$input, $output];
47+
48+
foreach (self::getSubscribedServices() as $id => $type) {
49+
if (0 === strpos($id, self::class.'::get')) {
50+
$arguments[] = $this->container->has($id) ? $this->container->get($id) : null;
51+
}
52+
}
53+
54+
return $this->exec(...$arguments);
55+
}
56+
57+
public static function getSubscribedServices(): array
58+
{
59+
$e = $m = null;
60+
61+
try {
62+
$m = new \ReflectionMethod(self::class, 'exec');
63+
} catch (\ReflectionException $e) {
64+
// rethrow below
65+
}
66+
67+
if (!$m || self::class !== $m->class) {
68+
throw new \LogicException(sprintf('Class "%s" should implement method "exec(InputInterface, OutputInterface, ...): int" when using "%s".', self::class, __TRAIT__), 0, $e);
69+
}
70+
71+
if (!(\ReflectionMethod::IS_PRIVATE & $m->getModifiers())) {
72+
throw new \LogicException(sprintf('Method "%s::exec()" should be private.', self::class));
73+
}
74+
$r = $m->getReturnType();
75+
76+
if ('int' !== ($r instanceof \ReflectionNamedType ? $r->getName() : (string) $r)) {
77+
throw new \LogicException(sprintf('Method "%s::exec()" should declare "int" as return type.', self::class));
78+
}
79+
80+
$services = \is_callable(['parent', __FUNCTION__]) ? parent::getSubscribedServices() : [];
81+
$i = 0;
82+
83+
foreach ($m->getParameters() as $i => $p) {
84+
$r = $p->getType();
85+
$type = $r instanceof \ReflectionNamedType ? $r->getName() : (string) $r;
86+
87+
if (0 === $i && InputInterface::class !== $type) {
88+
throw new \LogicException(sprintf('Method "%s::exec()" should declare argument #1 as "%s".', self::class, InputInterface::class));
89+
} elseif (1 === $i && OutputInterface::class !== $type) {
90+
throw new \LogicException(sprintf('Method "%s::exec()" should declare argument #2 as "%s".', self::class, OutputInterface::class));
91+
} elseif (2 <= $i) {
92+
$services[self::class.'::get'.$p->name] = ($p->allowsNull() ? '?' : '').$type;
93+
}
94+
}
95+
96+
if (1 > $i) {
97+
throw new \LogicException(sprintf('Method "%s::exec()" should declare 2 or more arguments.', self::class));
98+
}
99+
100+
return $services;
101+
}
102+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy