8000 bug #21072 [DI] Fix method autowiring in ResolveDefinitionTemplatesPa… · symfony/symfony@cd8983d · GitHub
[go: up one dir, main page]

Skip to content

Commit cd8983d

Browse files
fabpotlyrixx
authored andcommitted
bug #21072 [DI] Fix method autowiring in ResolveDefinitionTemplatesPass (dunglas)
This PR was merged into the 3.3-dev branch. Discussion ---------- [DI] Fix method autowiring in ResolveDefinitionTemplatesPass | Q | A | ------------- | --- | Branch? | master | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | n/a | License | MIT | Doc PR | n/a cc @nicolas-grekas Commits ------- 57661e4 [DI] Fix method autowiring in ResolveDefinitionTemplatesPass
2 parents ba932ae + 57661e4 commit cd8983d

File tree

8 files changed

+311
-20
lines changed

8 files changed

+311
-20
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
/*
4 8000 +
* 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\Bridge\Monolog\Formatter;
13+
14+
use Monolog\Formatter\FormatterInterface;
15+
use Symfony\Component\VarDumper\Cloner\VarCloner;
16+
17+
/**
18+
* @author Grégoire Pineau <lyrixx@lyrixx.info>
19+
*/
20+
class VarDumperFormatter implements FormatterInterface
21+
{
22+
private $cloner;
23+
24+
public function __construct(VarCloner $cloner = null)
25+
{
26+
$this->cloner = $cloner ?: new VarCloner();
27+
}
28+
29+
public function format(array $record)
30+
{
31+
$record['context'] = $this->cloner->cloneVar($record['context']);
32+
$record['extra'] = $this->cloner->cloneVar($record['extra']);
33+
34+
return $record;
35+
}
36+
37+
public function formatBatch(array $records)
38+
{
39+
foreach ($records as $k => $record) {
40+
$record[$k] = $this->format($record);
41+
}
42+
43+
return $records;
44+
}
45+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
3+
namespace Symfony\Bridge\Monolog\Handler;
4+
5+
use Monolog\Handler\AbstractProcessingHandler;
6+
use Monolog\Logger;
7+
use Monolog\Processor\UidProcessor;
8+
use Symfony\Bridge\Monolog\Formatter\VarDumperFormatter;
9+
10+
class ServerLogHandler extends AbstractProcessingHandler
11+
{
12+
protected $formatter;
13+
14+
private $host;
15+
16+
public function __construct($host, $level = Logger::DEBUG, $bubble = true)
17+
{
18+
parent::__construct($level, $bubble);
19+
20+
$this->host = $host;
21+
$this->formatter = new VarDumperFormatter();
22+
$this->pushProcessor(new UidProcessor());
23+
}
24+
25+
public function handle(array $record)
26+
{
27+
if (!$this->isHandling($record)) {
28+
return false;
29+
}
30+
31+
$record = $this->processRecord($record);
32+
33+
$this->write($record);
34+
35+
return false === $this->bubble;
36+
}
37+
38+
protected function write(array $record)
39+
{
40+
set_error_handler(array($this, 'nullErrorHandler'));
41+
$socket = fsockopen('tcp://'.$this->host, -1, $errno, $errstr, 1);
42+
restore_error_handler();
43+
44+
if (false === $socket) {
45+
return;
46+
}
47+
48+
$keys = array('uid', 'uuid', 'log_uuid');
49+
$logId = null;
50+
foreach ($keys as $key) {
51+
if (isset($record['extra'][$key])) {
52+
$logId = $record['extra'][$key];
53+
}
54+
}
55+
$formatted = $this->getFormatter()->format($record);
56+
$formatted['log_id'] = $logId;
57+
$formatted = base64_encode(serialize($formatted));
58+
59+
fwrite($socket, $formatted);
60+
fclose($socket);
61+
}
62+
63+
private function nullErrorHandler()
64+
{
65+
}
66+
}
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
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\Bundle\FrameworkBundle\Command;
13+
14+
use Symfony\Component\Console\Command\Command;
15+
use Symfony\Component\Console\Input\InputInterface;
16+
use Symfony\Component\Console\Input\InputOption;
17+
use Symfony\Component\Console\Output\OutputInterface;
18+
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
19+
use Symfony\Component\VarDumper\Cloner\Data;
20+
use Symfony\Component\VarDumper\Dumper\CliDumper;
21+
22+
/**
23+
* @author Grégoire Pineau <lyrixx@lyrixx.info>
24+
*/
25+
class ServerLogCommand extends Command
26+
{
27+
private $dumper;
28+
private $output;
29+
30+
private static $levelColorMap = array(
31+
100 => 'fg=white',
32+
200 => 'fg=green',
33+
250 => 'fg=blue',
34+
300 => 'fg=cyan',
35+
400 => 'fg=yellow',
36+
500 => 'fg=red',
37+
550 => 'fg=red',
38+
600 => 'fg=white;bg=red',
39+
);
40+
41+
private static $bgColor = array(
42+
'black',
43+
'blue',
44+
'cyan',
45+
'green',
46+
'magenta',
47+
'red',
48+
'white',
49+
'yellow',
50+
);
51+
52+
protected function configure()
53+
{
54+
$this
55+
->setName('server:log')
56+
->setDescription('Display log')
57+
->addOption('host', null, InputOption::VALUE_REQUIRED, 'The server host', '0:9911')
58+
->addOption('date-format', null, InputOption::VALUE_REQUIRED, 'The date format', 'H:i:s')
59+
->addOption('format', null, InputOption::VALUE_REQUIRED, 'The line format', '%s <%s>%-9s</> <options=bold>%-8.8s</> %s')
60+
->addOption('show-context', null, InputOption::VALUE_NONE, 'Display the context')
61+
->addOption('show-extra', null, InputOption::VALUE_NONE, 'Display the extra')
62+
->addOption('filter', null, InputOption::VALUE_REQUIRED, 'An expression to filter log. Example: record[\'level\'] > 200 or record[\'channel\'] in [\'app\', \'doctrine\']"')
63+
;
64+
}
65+
66+
protected function initialize(InputInterface $input, OutputInterface $output)
67+
{
68+
$this->dumper = new CliDumper();
69+
$this->dumper->setOutput($this->output = fopen('php://memory', 'r+b'));
70+
71+
$this->el = new ExpressionLanguage();
72+
}
73+
74+
protected function execute(InputInterface $input, OutputInterface $output)
75+
{
76+
$logs = $this->getLogs($input);
77+
78+
$filter = $input->getOption('filter');
79+
80+
foreach ($logs as $message) {
81+
$record = unserialize(base64_decode($message));
82+
83+
// Impossible to decode the message, give up.
84+
if (false === $record) {
85+
continue;
86+
}
87+
88+
if ($filter && !$this->el->evaluate($filter, $record)) {
89+
continue;
90+
}
91+
92+
$this->displayLog($input, $output, $record);
93+
}
94+
}
95+
96+
private function getLogs(InputInterface $input)
97+
{
98+
$socket = stream_socket_server($input->getOption('host'), $errno, $errstr);
99+
100+
if (!$socket) {
101+
throw new \RuntimeException(sprintf('Impossible to start the server: "%s (%s)".', $errstr, $errno));
102+
}
103+
104+
while ($client = stream_socket_accept($socket, -1)) {
105+
$message = '';
106+
107+
while (false !== ($buffer = fgets($client, 65535))) {
108+
$message .= $buffer;
109+
}
110+
111+
// Impossible to read the whole message, give up.
112+
if (!feof($client)) {
113+
fclose($client);
114+
115+
continue;
116+
}
117+
118+
fclose($client);
119+
120+
yield $message;
121+
}
122+
}
123+
124+
private function displayLog(InputInterface $input, OutputInterface $output, array $record)
125+
{
126+
$record = $this->replacePlaceHolder($output, $record);
127+
128+
$format = $input->getOption('format');
129+
$date = $record['datetime']->format($input->getOption('date-format'));
130+
$clientId = unpack('H*', $record['log_id'])[1];
131+
$logBlock = sprintf('<bg=%s> </>', self::$bgColor[$clientId % 8]);
132+
$levelColor = self::$levelColorMap[$record['level']];
133+
$message = $logBlock.sprintf($format, $date, $levelColor, $record['level_name'], $record['channel'], $record['message']);
134+
135+
$output->writeln($message);
136+
137+
if ($input->getOption('show-context') && $record['context']->getRawData()[0][0]) {
138+
$output->writeln(sprintf('%sContext %s', $logBlock, $this->dumpData($output, $record['context'])));
139+
}
140+
if ($input->getOption('show-extra') && $record['extra']->getRawData()[0][0]) {
141+
$output->writeln(sprintf('%sExtra %s', $logBlock, $this->dumpData($output, $record['extra'])));
142+
}
143+
}
144+
145+
private function replacePlaceHolder(OutputInterface $output, array $record)
146+
{
147+
$message = $record['message'];
148+
149+
if (false === strpos($message, '{')) {
150+
return $record;
151+
}
152+
153+
$context = $record['context'];
154+
155+
$replacements = array();
156+
foreach ($context->getRawData()[1] as $k => $v) {
157+
$replacements['"{'.$k.'}"'] = sprintf('<comment>%s</>', $this->dumpData($output, $context->seek($k), false));
158+
}
159+
160+
$record['message'] = strtr($message, $replacements);
161+
162+
return $record;
163+
}
164+
165+
public function dumpData(OutputInterface $output, Data $data, $colors = true, $maxDepth = 0)
166+
{
167+
if ($output->isDecorated()) {
168+
$this->dumper->setColors($colors);
169+
}
170+
171+
$this->dumper->dump($data);
172+
173+
$dump = stream_get_contents($this->output, -1, 0);
174+
rewind($this->output);
175+
ftruncate($this->output, 0);
176+
177+
return rtrim($dump);
178+
}
179+
}

src/Symfony/Component/DependencyInjection/ChildDefinition.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,11 @@ public function setDeprecated($boolean = true, $template = null)
137137
/**
138138
* {@inheritdoc}
139139
*/
140-
public function setAutowired($autowired)
140+
public function setAutowiredMethods(array $autowiredMethods)
141141
{
142-
$this->changes['autowire'] = true;
142+
$this->changes['autowired_methods'] = true;
143143

144-
return parent::setAutowired($autowired);
144+
return parent::setAutowiredMethods($autowiredMethods);
145145
}
146146

147147
/**

src/Symfony/Component/DependencyInjection/Compiler/ResolveDefinitionTemplatesPass.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ private function doResolveDefinition(ContainerBuilder $container, ChildDefinitio
141141
$def->setFile($parentDef->getFile());
142142
$def->setPublic($parentDef->isPublic());
143143
$def->setLazy($parentDef->isLazy());
144-
$def->setAutowired($parentDef->isAutowired());
144+
$def->setAutowiredMethods($parentDef->getAutowiredMethods());
145145

146146
// overwrite with values specified in the decorator
147147
$changes = $definition->getChanges();
@@ -166,8 +166,8 @@ private function doResolveDefinition(ContainerBuilder $container, ChildDefinitio
166166
if (isset($changes['deprecated'])) {
167167
$def->setDeprecated($definition->isDeprecated(), $definition->getDeprecationMessage('%service_id%'));
168168
}
169-
if (isset($changes['autowire'])) {
170-
$def->setAutowired($definition->isAutowired());
169+
if (isset($changes['autowired_methods'])) {
170+
$def->setAutowiredMethods($definition->getAutowiredMethods());
171171
}
172172
if (isset($changes['decorated_service'])) {
173173
$decoratedService = $definition->getDecoratedService();
@@ -199,7 +199,7 @@ private function doResolveDefinition(ContainerBuilder $container, ChildDefinitio
199199
}
200200

201201
// append method calls
202-
if (count($calls = $definition->getMethodCalls()) > 0) {
202+
if ($calls = $definition->getMethodCalls()) {
203203
$def->setMethodCalls(array_merge($def->getMethodCalls(), $calls));
204204
}
205205

src/Symfony/Component/DependencyInjection/Tests/ChildDefinitionTest.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,14 @@ public function testSetLazy()
7070
$this->assertSame(array('lazy' => true), $def->getChanges());
7171
}
7272

73-
public function testSetAutowired()
73+
public function testSetAutowiredMethods()
7474
{
7575
$def = new ChildDefinition('foo');
7676

7777
$this->assertFalse($def->isAutowired());
78-
$this->assertSame($def, $def->setAutowired(false));
79-
$this->assertFalse($def->isAutowired());
80-
$this->assertSame(array('autowire' => true), $def->getChanges());
78+
$this->assertSame($def, $def->setAutowiredMethods(array('foo', 'bar')));
79+
$this->assertEquals(array('foo', 'bar'), $def->getAutowiredMethods());
80+
$this->assertSame(array('autowired_methods' => true), $def->getChanges());
8181
}
8282

8383
public function testSetArgument()

src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveDefinitionTemplatesPassTest.php

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -214,30 +214,31 @@ public function testSetAutowiredOnServiceHasParent()
214214
{
215215
$container = new ContainerBuilder();
216216

217-
$container->register('parent', 'stdClass');
217+
$container->register('parent', 'stdClass')
218+
->setAutowiredMethods(array('foo', 'bar'));
218219

219220
$container->setDefinition('child1', new ChildDefinition('parent'))
220-
->setAutowired(true)
221+
->setAutowiredMethods(array('baz'))
221222
;
222223

223224
$this->process($container);
224225

225-
$this->assertTrue($container->getDefinition('child1')->isAutowired());
226+
$this->assertEquals(array('baz'), $container->getDefinition('child1')->getAutowiredMethods());
226227
}
227228

228229
public function testSetAutowiredOnServiceIsParent()
229230
{
230231
$container = new ContainerBuilder();
231232

232233
$container->register('parent', 'stdClass')
233-
->setAutowired(true)
234+
->setAutowiredMethods(array('__construct', 'set*'))
234235
;
235236

236237
$container->setDefinition('child1', new ChildDefinition('parent'));
237238

238239
$this->process($container);
239240

240-
$this->assertTrue($container->getDefinition('child1')->isAutowired());
241+
$this->assertEquals(array('__construct', 'set*'), $container->getDefinition('child1')->getAutowiredMethods());
241242
}
242243

243244
public function testDeepDefinitionsResolving()

0 commit comments

Comments
 (0)
0