Completed
Push — master ( 714831...2c4c1f )
by Peter
23:25
created

FileWalker::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 12
ccs 0
cts 11
cp 0
rs 9.4285
cc 2
eloc 7
nc 2
nop 3
crap 6
1
<?php
2
3
/*
4
 * To change this license header, choose License Headers in Project Properties.
5
 * To change this template file, choose Tools | Templates
6
 * and open the template in the editor.
7
 */
8
9
namespace Maslosoft\Addendum\Utilities;
10
11
use DirectoryIterator;
12
13
/**
14
 * FileWalker
15
 *
16
 * This walks recursivelly on symlinks too, with loop detection.
17
 *
18
 * This class is meant to replace AnnotationUtility::fileWalker method.
19
 *
20
 * @author Piotr Maselkowski <pmaselkowski at gmail.com>
21
 */
22
class FileWalker
23
{
24
25
	/**
26
	 * Pahts to scan
27
	 * @var string[]
28
	 */
29
	private $paths = [];
30
31
	/**
32
	 * Patterns to match for annotations
33
	 * @var string[]
34
	 */
35
	private $patterns = [];
36
37
	/**
38
	 * Callback to execute on file
39
	 * @var callback
40
	 */
41
	private $callback;
42
43
	/**
44
	 * List of visited real paths
45
	 * @var string[]
46
	 */
47
	private $visited = [];
48
49
	public function __construct($annotations, $callback, $paths)
50
	{
51
		$this->paths = $paths;
52
		$this->callback = $callback;
53
		$this->patterns = [];
54
55
		foreach ($annotations as $annotation)
56
		{
57
			$annotation = preg_replace('~^@~', '', $annotation);
58
			$this->patterns[] = sprintf('~@%s~', $annotation);
59
		}
60
	}
61
62
	public function walk()
63
	{
64
		foreach ($this->paths as $path)
65
		{
66
			$this->scan($path);
67
		}
68
	}
69
70
	private function scan($path)
71
	{
72
		// Check if should be visited
73
		$real = realpath($path);
74
		if (!empty($this->visited[$real]))
75
		{
76
			return;
77
		}
78
		// Mark real path as visited
79
		$this->visited[$real] = true;
80
81
		// Scan real path
82
		$iterator = new DirectoryIterator($real);
83
		foreach ($iterator as $info)
84
		{
85
			if ($info->isDot())
86
			{
87
				continue;
88
			}
89
90
			// Recurse, loop prevention check is on top of this function
91
			if ($info->isDir())
92
			{
93
				$this->scan($info->getPathname());
94
				continue;
95
			}
96
97
			$file = $info->getPathname();
98
99
			// Check if should be processed
100
			if (!empty($this->visited[$file]))
101
			{
102
				continue;
103
			}
104
105
			// Mark as processed
106
			$this->visited[$file] = true;
107
108
			// Only php
109
			if (!preg_match('~^.+\.php$~i', $file))
110
			{
111
				continue;
112
			}
113
114
			$parse = false;
115
116
			if (is_readable($file))
117
			{
118
				$contents = file_get_contents($file);
119
			}
120
			else
121
			{
122
				// TODO Log this
123
				continue;
124
			}
125
			foreach ($this->patterns as $pattern)
126
			{
127
				if ($parse)
128
				{
129
					continue;
130
				}
131
				if (preg_match($pattern, $contents))
132
				{
133
					$parse = true;
134
				}
135
			}
136
			if (!$parse)
137
			{
138
				continue;
139
			}
140
			call_user_func($this->callback, $file, $contents);
141
		}
142
	}
143
144
}
145