Completed
Push — master ( 470c23...605cf4 )
by Richard
08:11
created

Indexer   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 162
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 12

Test Coverage

Coverage 77.03%

Importance

Changes 0
Metric Value
wmc 16
lcom 1
cbo 12
dl 0
loc 162
ccs 57
cts 74
cp 0.7703
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 11 1
B index_directory() 0 24 4
A init_flightcontrol() 0 5 1
A index_file() 0 11 2
A index_content() 0 16 2
A on_enter_definition() 0 4 1
A on_enter_misc() 0 4 1
A on_enter_something() 0 15 4
1
<?php
2
/******************************************************************************
3
 * An implementation of dicto (scg.unibe.ch/dicto) in and for PHP.
4
 *
5
 * Copyright (c) 2016, 2015 Richard Klees <[email protected]>
6
 *
7
 * This software is licensed under The MIT License. You should have received
8
 * a copy of the license along with the code.
9
 */
10
11
namespace Lechimp\Dicto\Indexer;
12
13
use Lechimp\Dicto\Regexp;
14
use Psr\Log\LoggerInterface as Log;
15
use League\Flysystem\Adapter\Local;
16
use League\Flysystem\Filesystem;
17
use Lechimp\Flightcontrol\Flightcontrol;
18
use Lechimp\Flightcontrol\File;
19
use Lechimp\Flightcontrol\FSObject;
20
21
/**
22
 * Creates an index of source files.
23
 */
24
class Indexer implements ListenerRegistry {
25
    /**
26
     * @var Log
27
     */
28
    protected $log;
29
30
    /**
31
     * @var Insert
32
     */
33
    protected $insert;
34
35
    /**
36
     * @var \PhpParser\Parser
37
     */
38
    protected $parser;
39
40
    /**
41
     * @var array   string => array()
42
     */
43
    protected $listeners_enter_definition;
44
45
    /**
46
     * @var array   string => array()
47
     */
48
    protected $listeners_enter_misc;
49
50 53
    public function __construct(Log $log, \PhpParser\Parser $parser, Insert $insert) {
51 53
        $this->log = $log;
52 53
        $this->parser = $parser;
53 53
        $this->insert = $insert;
54 53
        $this->listeners_enter_definition = array
55 53
            ( 0 => array()
56 53
            );
57 53
        $this->listeners_enter_misc = array
58 53
            ( 0 => array()
59 53
            );
60 53
    }
61
62
    /**
63
     * Index a directory.
64
     *
65
     * @param   string  $path
66
     * @param   array   $ignore_paths
67
     * @return  null
68
     */
69 7
    public function index_directory($path, array $ignore_paths) {
70
        $ignore_paths_re = array_map(function($ignore) {
71 7
            return new Regexp($ignore);
72 7
        }, $ignore_paths);
73 7
        $fc = $this->init_flightcontrol($path);
74 7
        $fc->directory("/")
75 7
            ->recurseOn()
76
            ->filter(function(FSObject $obj) use (&$ignore_paths_re) {
77 7
                foreach ($ignore_paths_re as $re) {
78 7
                    if ($re->match($obj->path())) {
79 7
                        return false;
80
                    }
81 7
                }
82 7
                return true;
83 7
            })
84 7
            ->foldFiles(null, function($_, File $file) use ($path) {
85
                try {
86 7
                    $this->index_file($path, $file->path());
87
                }
88 7
                catch (\PhpParser\Error $e) {
89
                    $this->log->error("in ".$file->path().": ".$e->getMessage());
90
                }
91 7
            });
92 7
    }
93
94
    /**
95
     * Initialize the filesystem abstraction.
96
     *
97
     * @return  Flightcontrol
98
     */
99 7
    public function init_flightcontrol($path) {
100 7
        $adapter = new Local($path, LOCK_EX, Local::SKIP_LINKS);
101 7
        $flysystem = new Filesystem($adapter);
102 7
        return new Flightcontrol($flysystem);
103
    }
104
105
    /**
106
     * @param   string  $base_dir
107
     * @param   string  $path
108
     * @return  null
109
     */
110
    public function index_file($base_dir, $path) {
111
        assert('is_string($base_dir)');
112
        assert('is_string($path)');
113
        $this->log->info("indexing: ".$path);
114
        $full_path = "$base_dir/$path";
115
        $content = file_get_contents($full_path);
116
        if ($content === false) {
117
            throw \InvalidArgumentException("Can't read file $path.");
118
        }
119
        $this->index_content($path, $content);
120
    }
121
122
    /**
123
     * @param   string  $path
124
     * @param   string  $content
125
     * @return  null
126
     */
127 53
    public function index_content($path, $content) {
128 53
        assert('is_string($path)');
129 53
        assert('is_string($content)');
130
131 53
        $stmts = $this->parser->parse($content);
132 53
        if ($stmts === null) {
133
            throw new \RuntimeException("Can't parse file $path.");
134
        }
135
136 53
        $traverser = new \PhpParser\NodeTraverser;
137 53
        $location = new LocationImpl($path, $content);
138 53
        $visitor = new ASTVisitor($location, $this->insert, $this->listeners_enter_definition, $this->listeners_enter_misc); 
139 53
        $traverser->addVisitor($visitor);
140
141 53
        $traverser->traverse($stmts);
142 53
    }
143
144
   // from ListenerRegistry 
145
146
    /**
147
     * @inheritdoc
148
     */
149
    public function on_enter_definition($types, \Closure $listener) {
150
        $this->on_enter_something("listeners_enter_definition", $types, $listener);
151
        return $this;
152
    }
153
154
    /**
155
     * @inheritdoc
156
     */
157 25
    public function on_enter_misc($classes, \Closure $listener) {
158 25
        $this->on_enter_something("listeners_enter_misc", $classes, $listener);
159 25
        return $this;
160
    }
161
162
    // generalizes over over on_enter
163
164
    /**
165
     * TODO: Maybe remove this in favour of duplicates.
166
     *
167
     * @param   string      $what
168
     * @param   array|null  $things
169
     */
170 25
    protected function on_enter_something($what, $things, \Closure $listener) {
171 25
        $loc = &$this->$what;
172 25
        if ($things === null) {
173
            $loc[0][] = $listener;
174
        }
175
        else {
176 25
            foreach ($things as $thing) {
177 25
                assert('is_string($thing)');
178 25
                if (!array_key_exists($thing, $loc)) {
179 25
                    $loc[$thing] = array();
180 25
                }
181 25
                $loc[$thing][] = $listener;
182 25
            }
183
        }
184 25
    }
185
}
186