Completed
Push — master ( 033afb...3ae743 )
by Nikita
02:22
created

RebuildCacheCommand::extractClassNameFromFile()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 19
rs 9.2
c 0
b 0
f 0
cc 4
eloc 12
nc 4
nop 1
1
<?php
2
3
namespace Taisiya\CoreBundle\Command;
4
5
use Symfony\Component\Console\Input\InputInterface;
6
use Symfony\Component\Console\Output\OutputInterface;
7
use Symfony\Component\Finder\Finder;
8
use Taisiya\CoreBundle\Composer\Event\EventSubscriberInterface;
9
use Taisiya\CoreBundle\Console\Style\TaisiyaStyle;
10
use Taisiya\CoreBundle\Exception\InvalidArgumentException;
11
use Taisiya\CoreBundle\Exception\NotReadableException;
12
use Taisiya\CoreBundle\Exception\RuntimeException;
13
use Taisiya\CoreBundle\Provider\ServiceProvider;
14
15
class RebuildCacheCommand extends Command
16
{
17
    protected function configure()
18
    {
19
        $this->setName('cache:rebuild')
20
            ->setDescription('Rebuild internal application cache');
21
    }
22
23
    protected function execute(InputInterface $input, OutputInterface $output)
24
    {
25
        $io = new TaisiyaStyle($input, $output);
26
27
        $this->rebuildComposerSubscribersCache($io);
28
        $this->rebuildBundlesCache($io);
29
        $this->rebuildCommandsCache($io);
30
    }
31
32
    /**
33
     * @param TaisiyaStyle $io
34
     */
35 View Code Duplication
    final protected function rebuildComposerSubscribersCache(TaisiyaStyle $io): void
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
36
    {
37
        $io->isVerbose() && $io->writeln('Rebuild Composer subscribers cache');
38
39
        $subscribers = [];
40
41
        $finder = Finder::create()
42
            ->in(TAISIYA_ROOT)
43
            ->path('/(src|vendor)/')
44
            ->files()
45
            ->name('*Subscriber.php');
46
47
        foreach ($finder as $k => $file) {
48
            $subscriberClass = $this->extractClassNameFromFile($file->getPathname());
49
            try {
50
                $reflectionClass = new \ReflectionClass($subscriberClass);
51
            } catch (\ReflectionException $e) {
52
                continue;
53
            }
54
            if (!$reflectionClass->isAbstract() && $reflectionClass->isSubclassOf(EventSubscriberInterface::class)) {
55
                $io->isVerbose() && $io->writeln('  + '.$subscriberClass);
56
                $subscribers[] = $subscriberClass;
57
            }
58
        }
59
60
        $this->putDataToCacheFile('composer_subscribers.cache.php', $subscribers);
61
        $io->isVerbose() && $io->writeln('  Subscribers saved to <info>composer_subscribers.cache.php</info>');
62
    }
63
64
    /**
65
     * @param TaisiyaStyle $io
66
     */
67 View Code Duplication
    final protected function rebuildBundlesCache(TaisiyaStyle $io): void
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
68
    {
69
        $io->isVerbose() && $io->writeln('Rebuild bundles cache');
70
71
        $bundles = [];
72
73
        $finder = Finder::create()
74
            ->in(TAISIYA_ROOT)
75
            ->path('/(src|vendor)/')
76
            ->files()
77
            ->name('*ServiceProvider.php');
78
79
        foreach ($finder as $k => $file) {
80
            $bundleServiceProvider = $this->extractClassNameFromFile($file->getPathname());
81
            $reflectionClass = new \ReflectionClass($bundleServiceProvider);
82
            if (!$reflectionClass->isAbstract() && $reflectionClass->isSubclassOf(ServiceProvider::class)) {
83
                $io->isVerbose() && $io->writeln('  + '.$bundleServiceProvider);
84
                $bundles[] = $bundleServiceProvider;
85
            }
86
        }
87
88
        $this->putDataToCacheFile('bundles.cache.php', $bundles);
89
        $io->isVerbose() && $io->writeln('  Bundles saved to <info>bundles.cache.php</info>');
90
    }
91
92
    /**
93
     * @param TaisiyaStyle $io
94
     */
95 View Code Duplication
    final protected function rebuildCommandsCache(TaisiyaStyle $io): void
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
96
    {
97
        $io->isVerbose() && $io->writeln('Rebuild commands cache');
98
99
        $commands = [];
100
101
        $finder = Finder::create()
102
            ->in(TAISIYA_ROOT)
103
            ->path('/(src|vendor)/')
104
            ->files()
105
            ->name('*Command.php');
106
107
        foreach ($finder as $k => $file) {
108
            $commandClass = $this->extractClassNameFromFile($file->getPathname());
109
            try {
110
                $reflectionClass = new \ReflectionClass($commandClass);
111
            } catch (\ReflectionException $e) {
112
                continue;
113
            }
114
            if (!$reflectionClass->isAbstract() && $reflectionClass->isSubclassOf(Command::class)) {
115
                $io->isVerbose() && $io->writeln('  + '.$commandClass);
116
                $commands[] = $commandClass;
117
            }
118
        }
119
120
        $this->putDataToCacheFile('commands.cache.php', $commands);
121
        $io->isVerbose() && $io->writeln('  Commands saved to <info>commands.cache.php</info>');
122
    }
123
124
    /**
125
     * @param string $filepath
126
     * @throws RuntimeException
127
     * @return string
128
     */
129
    final protected function extractClassNameFromFile(string $filepath): string
130
    {
131
        $contents = $this->getFileContents($filepath);
132
133
        preg_match('/namespace\s+(.+?)\;/', $contents, $namespace);
134
        if (!is_array($namespace) || !array_key_exists(1, $namespace)) {
135
            $namespace = null;
136
        } else {
137
            $namespace = $namespace[1];
138
        }
139
140
        preg_match('/class\s+(\w+)/', $contents, $class);
141
        if (!array_key_exists(1, $class)) {
142
            throw new RuntimeException('Couldn\'t extract class from file '.$filepath);
143
        }
144
        $class = $class[1];
145
146
        return preg_replace('/\\+/', '\\', implode('\\', ['', $namespace, $class]));
147
    }
148
149
    /**
150
     * @param string $filepath
151
     * @throws InvalidArgumentException
152
     * @throws NotReadableException
153
     * @throws RuntimeException
154
     * @return string
155
     */
156
    final protected function getFileContents(string $filepath): string
157
    {
158
        if (!file_exists($filepath)) {
159
            throw new InvalidArgumentException('File '.$filepath.' not exists');
160
        } elseif (!is_file($filepath)) {
161
            throw new InvalidArgumentException('The '.$filepath.' is not a regular file');
162
        } elseif (!is_readable($filepath)) {
163
            throw new NotReadableException('File '.$filepath.' not readable');
164
        }
165
166
        $contents = file_get_contents($filepath);
167
168
        if ($contents === false) {
169
            throw new RuntimeException('Couldn\'t get contents from file '.$filepath);
170
        }
171
172
        return $contents;
173
    }
174
175
    /**
176
     * @param string $filename
177
     * @param array $data
178
     * @throws RuntimeException
179
     */
180
    final protected function putDataToCacheFile(string $filename, array $data): void
181
    {
182
        $cacheDir = TAISIYA_ROOT.'/var/cache';
183
        if (!file_exists($cacheDir)) {
184
            if (!mkdir($cacheDir, 0777, true)) {
185
                throw new RuntimeException('Couldn\'t create directory '.$cacheDir);
186
            }
187
        }
188
        if (!file_put_contents($cacheDir.'/'.$filename, "<?php\n\nreturn ".var_export($data, true).";\n")) {
189
            throw new RuntimeException('Couldn\'t write contents to file '.$cacheDir.'/'.$filename);
190
        }
191
    }
192
}
193