Passed
Push — master ( 65ca3f...66b084 )
by Radosław
02:04
created

CreateFunctionCommand::reloadBundlesFile()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 26
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 17
nc 1
nop 0
dl 0
loc 26
rs 9.7
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace Phln\Build\Command;
5
6
use Illuminate\Console\Command;
7
use Illuminate\View\Factory;
8
use Symfony\Component\Finder\Finder;
9
use Symfony\Component\Finder\SplFileInfo;
10
use const phln\fn\T;
11
use const phln\object\keys;
12
use function phln\string\match;
13
use function phln\collection\{
14
    filter
15
};
16
use function phln\fn\{
17
    compose, pipe
18
};
19
use function phln\object\{
20
    prop
21
};
22
23
class CreateFunctionCommand extends Command
24
{
25
    protected $signature = 'create:fn {ns} {name}';
26
27
    /**
28
     * @var Factory
29
     */
30
    private $view;
31
32
    public function __construct(Factory $view)
33
    {
34
        parent::__construct();
35
        $this->view = $view;
36
    }
37
38
    public function handle()
39
    {
40
        $ns = $this->argument('ns');
41
        $name = $this->argument('name');
42
43
        $this->validateFunctionName($name);
44
45
        $this->output->writeln(sprintf(
46
            'Function created at: <info>%s</info>',
47
            $this->createFunctionSource($ns, $name)
48
        ));
49
50
        $this->output->writeln(sprintf(
51
            'Test created at: <info>%s</info>',
52
            $this->createTestSource($ns, $name)
53
        ));
54
55
        $this->reloadBundlesFile();
56
        $this->output->writeln('Bundle file reloaded');
57
    }
58
59
    private function validateFunctionName($name)
60
    {
61
        $collisions = pipe([
62
            compose([keys, prop('user'), '\\get_defined_constants', T]),
63
            filter(match("/^phln\\\\.+\\\\${name}$/"))
64
        ])($name);
65
66
        if (false === empty($collisions)) {
67
            throw new \Exception("Name [{$name}] is in use");
68
        }
69
    }
70
71
    private function createFunctionSource($ns, $name)
72
    {
73
        return $this->generateFile('function', 'src', $ns, $name);
74
    }
75
76
    private function createTestSource($ns, $name)
77
    {
78
        return $this->generateFile('function-test', 'tests', $ns, $name, ucfirst($name).'Test');
79
    }
80
81
    private function generateFile($template, $location, $ns, $name, $fileName = null)
82
    {
83
        $contents = $this->view->make($template)
84
            ->with(compact('ns', 'name'))
85
            ->render();
86
87
        $path = sprintf(
88
            '%s/../../%s/%s/%s.php',
89
            __DIR__,
90
            $location,
91
            $ns,
92
            $fileName ?: $name
93
        );
94
        $dir = dirname($path);
95
96
        if (false === is_dir($dir)) {
97
            mkdir($dir, 0755, true);
98
        }
99
100
        file_put_contents($path, $contents);
101
102
        return realpath($path);
103
    }
104
105
    private function reloadBundlesFile()
106
    {
107
        $finder = Finder::create()->in([__DIR__.'/../../src'])
108
            ->name('*.php')
109
            ->depth(1);
110
111
        $files = collect($finder)
112
            ->map(function (SplFileInfo $file) {
113
                $pathname = $file->getRelativePathname();
114
                list ($ns, $name) = explode(DIRECTORY_SEPARATOR, $pathname);
115
116
                return compact('ns', 'name');
117
            })
118
            ->values()
119
            ->sort(function ($a, $b) {
120
                $byNs = strcmp($a['ns'], $b['ns']);
121
                $byName = strcmp($a['name'], $b['name']);
122
123
                return (0 === $byNs) ? $byName : $byNs;
124
            });
125
126
        $contents = $this->view->make('bundle')
127
            ->with(compact('files'))
128
            ->render();
129
130
        file_put_contents(__DIR__.'/../../src/bundle.php', $contents);
131
    }
132
}
133