1
|
|
|
<?php |
2
|
|
|
/* |
3
|
|
|
* Go! AOP framework |
4
|
|
|
* |
5
|
|
|
* @copyright Copyright 2015, Lisachenko Alexander <[email protected]> |
6
|
|
|
* |
7
|
|
|
* This source file is subject to the license that is bundled |
8
|
|
|
* with this source code in the file LICENSE. |
9
|
|
|
*/ |
10
|
|
|
|
11
|
|
|
namespace Go\Console\Command; |
12
|
|
|
|
13
|
|
|
use Go\Aop\Advisor; |
14
|
|
|
use Go\Aop\Pointcut; |
15
|
|
|
use Go\Core\AdviceMatcher; |
16
|
|
|
use Go\Core\AspectContainer; |
17
|
|
|
use Go\Core\AspectLoader; |
18
|
|
|
use Go\Instrument\FileSystem\Enumerator; |
19
|
|
|
use Go\ParserReflection\ReflectionFile; |
20
|
|
|
use ReflectionClass; |
21
|
|
|
use Symfony\Component\Console\Input\InputInterface; |
22
|
|
|
use Symfony\Component\Console\Input\InputOption; |
23
|
|
|
use Symfony\Component\Console\Output\OutputInterface; |
24
|
|
|
use Symfony\Component\Console\Style\SymfonyStyle; |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* Console command to debug an advisors |
28
|
|
|
*/ |
29
|
|
|
class DebugAdvisorCommand extends BaseAspectCommand |
30
|
|
|
{ |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* {@inheritDoc} |
34
|
|
|
*/ |
35
|
|
|
protected function configure() |
36
|
|
|
{ |
37
|
|
|
parent::configure(); |
38
|
|
|
$this |
39
|
|
|
->setName('debug:advisor') |
40
|
|
|
->addOption('advisor', null, InputOption::VALUE_OPTIONAL, "Identifier of advisor") |
41
|
|
|
->setDescription("Provides an interface for checking and debugging advisors") |
42
|
|
|
->setHelp(<<<EOT |
43
|
|
|
Allows to query an information about matching joinpoints for specified advisor. |
44
|
|
|
EOT |
45
|
|
|
); |
46
|
|
|
} |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* {@inheritDoc} |
50
|
|
|
*/ |
51
|
|
|
protected function execute(InputInterface $input, OutputInterface $output) |
52
|
|
|
{ |
53
|
|
|
parent::execute($input, $output); |
54
|
|
|
$io = new SymfonyStyle($input, $output); |
55
|
|
|
$io->title('Advisor debug information'); |
56
|
|
|
|
57
|
|
|
$advisorId = $input->getOption('advisor'); |
58
|
|
|
if (!$advisorId) { |
59
|
|
|
$this->showAdvisorsList($io); |
60
|
|
|
} else { |
61
|
|
|
$this->showAdvisorInformation($io, $advisorId); |
62
|
|
|
} |
63
|
|
|
} |
64
|
|
|
|
65
|
|
|
private function showAdvisorsList(SymfonyStyle $io) |
66
|
|
|
{ |
67
|
|
|
$io->writeln('List of registered advisors in the container'); |
68
|
|
|
|
69
|
|
|
$aspectContainer = $this->aspectKernel->getContainer(); |
70
|
|
|
$advisors = $this->loadAdvisorsList($aspectContainer); |
71
|
|
|
|
72
|
|
|
$tableRows = []; |
73
|
|
|
foreach ($advisors as $id => $advisor) { |
74
|
|
|
list(,$id) = explode('.', $id, 2); |
75
|
|
|
$advice = $advisor->getAdvice(); |
76
|
|
|
$expression = ''; |
77
|
|
|
try { |
78
|
|
|
$pointcutExpression = new \ReflectionProperty($advice, 'pointcutExpression'); |
79
|
|
|
$pointcutExpression->setAccessible('true'); |
80
|
|
|
$expression = $pointcutExpression->getValue($advice); |
81
|
|
|
} catch (\ReflectionException $e) { |
82
|
|
|
// nothing here, just ignore |
83
|
|
|
}; |
84
|
|
|
$tableRows[] = [$id, $expression]; |
85
|
|
|
} |
86
|
|
|
$io->table(['Id', 'Expression'], $tableRows); |
87
|
|
|
|
88
|
|
|
$io->writeln([ |
89
|
|
|
'If you want to query an information about concrete advisor, then just query it', |
90
|
|
|
'by adding <info>--advisor="Advisor\\Name"</info> to the command' |
91
|
|
|
]); |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
private function showAdvisorInformation(SymfonyStyle $io, $advisorId) |
95
|
|
|
{ |
96
|
|
|
$aspectContainer = $this->aspectKernel->getContainer(); |
97
|
|
|
|
98
|
|
|
/** @var AdviceMatcher $adviceMatcher */ |
99
|
|
|
$adviceMatcher = $aspectContainer->get('aspect.advice_matcher'); |
100
|
|
|
$this->loadAdvisorsList($aspectContainer); |
101
|
|
|
|
102
|
|
|
$advisor = $aspectContainer->getAdvisor($advisorId); |
103
|
|
|
$options = $this->aspectKernel->getOptions(); |
104
|
|
|
|
105
|
|
|
$enumerator = new Enumerator($options['appDir'], $options['includePaths'], $options['excludePaths']); |
106
|
|
|
|
107
|
|
|
$iterator = $enumerator->enumerate(); |
108
|
|
|
$totalFiles = iterator_count($iterator); |
109
|
|
|
$io->writeln("Total <info>{$totalFiles}</info> files to analyze."); |
110
|
|
|
$iterator->rewind(); |
111
|
|
|
|
112
|
|
|
foreach ($iterator as $file) { |
113
|
|
|
$reflectionFile = new ReflectionFile((string)$file); |
114
|
|
|
$reflectionNamespaces = $reflectionFile->getFileNamespaces(); |
115
|
|
|
foreach ($reflectionNamespaces as $reflectionNamespace) { |
116
|
|
|
foreach ($reflectionNamespace->getClasses() as $reflectionClass) { |
117
|
|
|
$advices = $adviceMatcher->getAdvicesForClass($reflectionClass, array($advisor)); |
118
|
|
|
if ($advices) { |
|
|
|
|
119
|
|
|
$this->writeInfoAboutAdvices($io, $reflectionClass, $advices); |
120
|
|
|
} |
121
|
|
|
} |
122
|
|
|
} |
123
|
|
|
} |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
private function writeInfoAboutAdvices(SymfonyStyle $io, ReflectionClass $reflectionClass, array $advices) |
127
|
|
|
{ |
128
|
|
|
$className = $reflectionClass->getName(); |
|
|
|
|
129
|
|
|
foreach ($advices as $type=>$typedAdvices) { |
|
|
|
|
130
|
|
|
foreach ($typedAdvices as $pointName=>$advice) { |
|
|
|
|
131
|
|
|
$io->writeln(" -> matching <comment>{$type} {$className}->{$pointName}</comment>"); |
132
|
|
|
} |
133
|
|
|
} |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
/** |
137
|
|
|
* Collects list of advisors from the container |
138
|
|
|
* |
139
|
|
|
* @param AspectContainer $aspectContainer Container instance |
140
|
|
|
* |
141
|
|
|
* @return Advisor[] List of advisors in the container |
142
|
|
|
*/ |
143
|
|
|
private function loadAdvisorsList(AspectContainer $aspectContainer) |
144
|
|
|
{ |
145
|
|
|
/** @var AspectLoader $aspectLoader */ |
146
|
|
|
$aspectLoader = $aspectContainer->get('aspect.cached.loader'); |
147
|
|
|
$aspects = $aspectLoader->getUnloadedAspects(); |
148
|
|
|
foreach ($aspects as $aspect) { |
149
|
|
|
$aspectLoader->loadAndRegister($aspect); |
150
|
|
|
} |
151
|
|
|
$advisors = $aspectContainer->getByTag('advisor'); |
152
|
|
|
|
153
|
|
|
return $advisors; |
154
|
|
|
} |
155
|
|
|
} |
156
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.