Completed
Push — master ( e57357...0c5664 )
by Alexander
9s
created

DebugAdvisorCommand::showAdvisorInformation()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 31
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 0
loc 31
ccs 0
cts 25
cp 0
rs 8.439
cc 5
eloc 19
nc 5
nop 2
crap 30
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\Core\AdviceMatcher;
15
use Go\Core\AspectContainer;
16
use Go\Core\AspectLoader;
17
use Go\Instrument\FileSystem\Enumerator;
18
use Go\ParserReflection\ReflectionFile;
19
use ReflectionClass;
20
use Symfony\Component\Console\Input\InputInterface;
21
use Symfony\Component\Console\Input\InputOption;
22
use Symfony\Component\Console\Output\OutputInterface;
23
use Symfony\Component\Console\Style\SymfonyStyle;
24
25
/**
26
 * Console command to debug an advisors
27
 */
28
class DebugAdvisorCommand extends BaseAspectCommand
29
{
30
31
    /**
32
     * {@inheritDoc}
33
     */
34
    protected function configure()
35
    {
36
        parent::configure();
37
        $this
38
            ->setName('debug:advisor')
39
            ->addOption('advisor', null, InputOption::VALUE_OPTIONAL, "Identifier of advisor")
40
            ->setDescription("Provides an interface for checking and debugging advisors")
41
            ->setHelp(<<<EOT
42
Allows to query an information about matching joinpoints for specified advisor.
43
EOT
44
            );
45
    }
46
47
    /**
48
     * {@inheritDoc}
49
     */
50
    protected function execute(InputInterface $input, OutputInterface $output)
51
    {
52
        parent::execute($input, $output);
53
        $io = new SymfonyStyle($input, $output);
54
        $io->title('Advisor debug information');
55
56
        $advisorId = $input->getOption('advisor');
57
        if (!$advisorId) {
58
            $this->showAdvisorsList($io);
59
        } else {
60
            $this->showAdvisorInformation($io, $advisorId);
61
        }
62
    }
63
64
    private function showAdvisorsList(SymfonyStyle $io)
65
    {
66
        $io->writeln('List of registered advisors in the container');
67
68
        $aspectContainer = $this->aspectKernel->getContainer();
69
        $advisors        = $this->loadAdvisorsList($aspectContainer);
70
71
        $tableRows = [];
72
        foreach ($advisors as $id => $advisor) {
73
            list(,$id) = explode('.', $id, 2);
74
            $advice     = $advisor->getAdvice();
75
            $expression = '';
76
            try {
77
                $pointcutExpression = new \ReflectionProperty($advice, 'pointcutExpression');
78
                $pointcutExpression->setAccessible('true');
79
                $expression = $pointcutExpression->getValue($advice);
80
            } catch (\ReflectionException $e) {
81
                // nothing here, just ignore
82
            };
83
            $tableRows[] = [$id, $expression];
84
        }
85
        $io->table(['Id', 'Expression'], $tableRows);
86
87
        $io->writeln([
88
            'If you want to query an information about concrete advisor, then just query it',
89
            'by adding <info>--advisor="Advisor\\Name"</info> to the command'
90
        ]);
91
    }
92
93
    private function showAdvisorInformation(SymfonyStyle $io, $advisorId)
94
    {
95
        $aspectContainer = $this->aspectKernel->getContainer();
96
97
        /** @var AdviceMatcher $adviceMatcher */
98
        $adviceMatcher = $aspectContainer->get('aspect.advice_matcher');
99
        $this->loadAdvisorsList($aspectContainer);
100
101
        $advisor = $aspectContainer->getAdvisor($advisorId);
102
        $options = $this->aspectKernel->getOptions();
103
104
        $enumerator = new Enumerator($options['appDir'], $options['includePaths'], $options['excludePaths']);
105
106
        $iterator   = $enumerator->enumerate();
107
        $totalFiles = iterator_count($iterator);
108
        $io->writeln("Total <info>{$totalFiles}</info> files to analyze.");
109
        $iterator->rewind();
110
111
        foreach ($iterator as $file) {
112
            $reflectionFile       = new ReflectionFile((string) $file);
113
            $reflectionNamespaces = $reflectionFile->getFileNamespaces();
114
            foreach ($reflectionNamespaces as $reflectionNamespace) {
115
                foreach ($reflectionNamespace->getClasses() as $reflectionClass) {
116
                    $advices = $adviceMatcher->getAdvicesForClass($reflectionClass, array($advisor));
117
                    if (!empty($advices)) {
118
                        $this->writeInfoAboutAdvices($io, $reflectionClass, $advices);
119
                    }
120
                }
121
            }
122
        }
123
    }
124
125
    private function writeInfoAboutAdvices(SymfonyStyle $io, ReflectionClass $reflectionClass, array $advices)
126
    {
127
        $className = $reflectionClass->getName();
128
        foreach ($advices as $type => $typedAdvices) {
129
            foreach ($typedAdvices as $pointName => $advice) {
130
                $io->writeln("  -> matching <comment>{$type} {$className}->{$pointName}</comment>");
131
            }
132
        }
133
    }
134
135
    /**
136
     * Collects list of advisors from the container
137
     *
138
     * @param AspectContainer $aspectContainer Container instance
139
     *
140
     * @return Advisor[] List of advisors in the container
141
     */
142
    private function loadAdvisorsList(AspectContainer $aspectContainer)
143
    {
144
        /** @var AspectLoader $aspectLoader */
145
        $aspectLoader   = $aspectContainer->get('aspect.cached.loader');
146
        $aspects        = $aspectLoader->getUnloadedAspects();
147
        foreach ($aspects as $aspect) {
148
            $aspectLoader->loadAndRegister($aspect);
149
        }
150
        $advisors = $aspectContainer->getByTag('advisor');
151
152
        return $advisors;
153
    }
154
}
155