Completed
Pull Request — master (#46)
by Jitendra
01:49
created

BaseCommand::getSourceClasses()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 3
nop 0
dl 0
loc 15
rs 10
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of the PHINT package.
5
 *
6
 * (c) Jitendra Adhikari <[email protected]>
7
 *     <https://github.com/adhocore>
8
 *
9
 * Licensed under MIT license.
10
 */
11
12
namespace Ahc\Phint\Console;
13
14
use Ahc\Cli\Input\Command;
15
use Ahc\Cli\IO\Interactor;
16
use Ahc\Phint\Util\Composer;
17
use Ahc\Phint\Util\Git;
18
use Ahc\Phint\Util\Metadata;
19
use Ahc\Phint\Util\Path;
20
21
abstract class BaseCommand extends Command
22
{
23
    /** @var string Full path of log file */
24
    protected $_logFile;
25
26
    /** @var string Current working dir */
27
    protected $_workDir;
28
29
    public function __construct()
30
    {
31
        $logFile = @\tempnam(\sys_get_temp_dir(), 'PHT') ?: '';
32
33
        $this->_logFile  = $logFile;
34
        $this->_pathUtil = new Path;
0 ignored issues
show
Bug Best Practice introduced by
The property _pathUtil does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
35
        $this->_workDir  = \realpath(\getcwd());
36
        $this->_git      = new Git(null, $logFile);
0 ignored issues
show
Bug Best Practice introduced by
The property _git does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
37
        $this->_composer = new Composer(null, $logFile);
0 ignored issues
show
Bug Best Practice introduced by
The property _composer does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
38
39
        $this->defaults();
40
        $this->onConstruct();
41
    }
42
43
    protected function onConstruct()
44
    {
45
        // ;)
46
    }
47
48
    protected function promptAll(Interactor $io, array $promptConfig)
49
    {
50
        $template = ['default' => null, 'choices' => [], 'retry' => 1, 'extra' => '', 'restore' => false];
51
52
        foreach ($this->missingOptions($promptConfig) as $name => $option) {
53
            $config  = ($promptConfig[$name] ?? []) + $template;
54
            $default = ($config['default'] ?? $option->default()) ?: null;
55
56
            if ($config['choices']) {
57
                $value = $io->choice($option->desc(), $config['choices'], $default);
58
            } else {
59
                $value = $io->prompt($option->desc() . $config['extra'], $default, null, $config['retry']);
60
            }
61
62
            if ($config['restore']) {
63
                $value = $config['choices'][$value] ?? $value;
64
            }
65
66
            $this->set($name, $value);
67
        }
68
    }
69
70
    protected function missingOptions(array $config)
71
    {
72
        return \array_filter($this->userOptions(), function ($name) use ($config) {
73
            return false !== ($config[$name] ?? null) && \in_array($this->$name, [null, []], true);
74
        }, \ARRAY_FILTER_USE_KEY);
75
    }
76
77
    protected function getCachePath(): string
78
    {
79
        if (!\Phar::running(false)) {
80
            return __DIR__ . '/../../.cache';
81
        }
82
83
        return $this->_pathUtil->getPhintPath('.cache');
84
    }
85
86
    protected function logging(string $mode = 'start')
87
    {
88
        if (!$logFile = $this->_logFile) {
89
            return;
90
        }
91
92
        if ('end' === $mode) {
93
            $this->app()->io()->comment("Check detailed logs at $logFile", true);
94
        } else {
95
            $this->app()->io()->comment("Logging to $logFile", true);
96
        }
97
    }
98
99
    protected function getTemplatePaths(array $parameters): array
100
    {
101
        // Phint provided path.
102
        $templatePaths = [\realpath(__DIR__ . '/../../resources')];
103
        $userPath      = $parameters['template'] ?? null;
104
105
        if (empty($userPath)) {
106
            return $templatePaths;
107
        }
108
109
        $userPath = $this->_pathUtil->expand($userPath, $this->_workDir);
110
111
        // User supplied path comes first.
112
        \array_unshift($templatePaths, $userPath);
113
114
        return $templatePaths;
115
    }
116
117
    protected function getClassesMetadata(): array
118
    {
119
        $metadata = [];
120
121
        foreach ($this->getSourceClasses() as $classFqcn) {
122
            if ([] === $meta = $this->getClassMetadata($classFqcn)) {
123
                continue;
124
            }
125
126
            $metadata[] = $meta;
127
        }
128
129
        return $metadata;
130
    }
131
132
    protected function getSourceClasses(): array
133
    {
134
        // Sorry psr-0!
135
        $namespaces = $this->_composer->config('autoload.psr-4');
136
137
        $srcPaths = [];
138
        foreach ($namespaces as $ns => $path) {
139
            if (\preg_match('!^(source|src|lib|class)/?!', $path)) {
140
                $srcPaths[] = $this->_pathUtil->join($this->_workDir, $path);
141
            } else {
142
                unset($namespaces[$ns]);
143
            }
144
        }
145
146
        return $this->_pathUtil->loadClasses($srcPaths, \array_keys($namespaces));
147
    }
148
149
    protected function getClassMetaData(string $classFqcn): array
150
    {
151
        $class = new \ReflectionClass($classFqcn);
152
153
        if (!$this->shouldGenerateFor($class)) {
154
            return [];
155
        }
156
157
        $metadata = (new Metadata)->forReflectionClass($class);
158
159
        return empty($metadata['methods']) ? [] : $metadata;
160
    }
161
162
    protected function shouldGenerateFor(\ReflectionClass $class): bool
163
    {
164
        if ($class->isSubclassOf(\Throwable::class)) {
165
            return false;
166
        }
167
168
        if ($this->abstract) {
0 ignored issues
show
Bug Best Practice introduced by
The property abstract does not exist on Ahc\Phint\Console\BaseCommand. Since you implemented __get, consider adding a @property annotation.
Loading history...
169
            return true;
170
        }
171
172
        return !$class->isInterface() && !$class->isAbstract();
173
    }
174
}
175