BaseCommand::getCachePath()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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