Tinker   A
last analyzed

Complexity

Total Complexity 14

Size/Duplication

Total Lines 103
Duplicated Lines 0 %

Importance

Changes 14
Bugs 0 Features 1
Metric Value
eloc 46
c 14
b 0
f 1
dl 0
loc 103
rs 10
wmc 14

6 Methods

Rating   Name   Duplication   Size   Complexity  
A cleanOutput() 0 5 1
A __construct() 0 7 1
A removeComments() 0 13 2
A execute() 0 13 1
A ignoreCommentsAndPhpTags() 0 18 5
A createShell() 0 26 4
1
<?php
2
3
namespace Spatie\WebTinker;
4
5
use Illuminate\Database\Eloquent\Model;
6
use Illuminate\Foundation\Application;
7
use Illuminate\Support\Collection;
8
use Laravel\Tinker\ClassAliasAutoloader;
9
use Psy\Configuration;
10
use Psy\ExecutionLoopClosure;
11
use Psy\Shell;
12
use Spatie\WebTinker\OutputModifiers\OutputModifier;
13
use Symfony\Component\Console\Output\BufferedOutput;
14
15
class Tinker
16
{
17
    /** @var \Symfony\Component\Console\Output\BufferedOutput */
18
    protected $output;
19
20
    /** @var \Psy\Shell */
21
    protected $shell;
22
23
    /** @var \Spatie\WebTinker\OutputModifiers\OutputModifier */
24
    protected $outputModifier;
25
26
    public function __construct(OutputModifier $outputModifier)
27
    {
28
        $this->output = new BufferedOutput();
29
30
        $this->shell = $this->createShell($this->output);
31
32
        $this->outputModifier = $outputModifier;
33
    }
34
35
    public function execute(string $phpCode): string
36
    {
37
        $phpCode = $this->removeComments($phpCode);
38
        
39
        $this->shell->addInput($phpCode);
40
41
        $closure = new ExecutionLoopClosure($this->shell);
42
43
        $closure->execute();
44
45
        $output = $this->cleanOutput($this->output->fetch());
46
47
        return $this->outputModifier->modify($output);
48
    }
49
50
    protected function createShell(BufferedOutput $output): Shell
51
    {
52
        $config = new Configuration([
53
            'updateCheck' => 'never',
54
            'configFile' => config('web-tinker.config_file') !== null ? base_path().'/'.config('web-tinker.config_file') : null,
55
        ]);
56
57
        $config->setHistoryFile(defined('PHP_WINDOWS_VERSION_BUILD') ? 'null' : '/dev/null');
58
59
        $config->getPresenter()->addCasters([
60
            Collection::class => 'Laravel\Tinker\TinkerCaster::castCollection',
61
            Model::class => 'Laravel\Tinker\TinkerCaster::castModel',
62
            Application::class => 'Laravel\Tinker\TinkerCaster::castApplication',
63
        ]);
64
65
        $shell = new Shell($config);
66
67
        $shell->setOutput($output);
68
69
        $composerClassMap = base_path('vendor/composer/autoload_classmap.php');
70
71
        if (file_exists($composerClassMap)) {
72
            ClassAliasAutoloader::register($shell, $composerClassMap);
73
        }
74
75
        return $shell;
76
    }
77
78
    public function removeComments(string $code): string
79
    {
80
        $tokens = collect(token_get_all("<?php\n".$code.'?>'));
81
82
        return $tokens->reduce(function ($carry, $token) {
83
            if (is_string($token)) {
84
                return $carry.$token;
85
            }
86
87
            $text = $this->ignoreCommentsAndPhpTags($token);
88
89
            return $carry.$text;
90
        }, '');
91
    }
92
93
    protected function ignoreCommentsAndPhpTags(array $token)
94
    {
95
        [$id, $text] = $token;
96
97
        if ($id === T_COMMENT) {
98
            return '';
99
        }
100
        if ($id === T_DOC_COMMENT) {
101
            return '';
102
        }
103
        if ($id === T_OPEN_TAG) {
104
            return '';
105
        }
106
        if ($id === T_CLOSE_TAG) {
107
            return '';
108
        }
109
110
        return $text;
111
    }
112
113
    protected function cleanOutput(string $output): string
114
    {
115
        $output = preg_replace('/(?s)(<aside.*?<\/aside>)|Exit:  Ctrl\+D/ms', '$2', $output);
116
117
        return trim($output);
118
    }
119
}
120