-
Notifications
You must be signed in to change notification settings - Fork 0
/
analyzer.php
215 lines (164 loc) · 5.25 KB
/
analyzer.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
<?php
class Element
{
private $id;
private $class;
private $title;
private $text;
private $rel;
private $tag;
public function __construct(DOMElement $domElement)
{
$this->tag = $domElement->tagName;
$this->id = $domElement->getAttribute('id');
$this->class = $domElement->getAttribute('class');
$this->title = $domElement->getAttribute('title');
$this->rel = $domElement->getAttribute('rel');
$this->text = trim($domElement->nodeValue);
}
public function getTag()
{
return $this->tag;
}
public function getId()
{
return $this->id;
}
public function getClass()
{
return $this->class;
}
public function getTitle()
{
return $this->title;
}
public function getRel()
{
return $this->rel;
}
public function getText()
{
return $this->text;
}
}
interface HtmlComparator
{
public function applies(Element $original, Element $new) : bool;
public function getScore() : int;
public function getApplicableOutput() : string;
}
class TextComparator implements HtmlComparator
{
public function applies(Element $original, Element $new) : bool
{
return $original->getText() == $new->getText();
}
public function getScore() : int
{
return 30;
}
public function getApplicableOutput() : string
{
return 'Element has same content as original -> ' . $this->getScore() . ' points.';
}
}
class TitleComparator implements HtmlComparator
{
public function applies(Element $original, Element $new) : bool
{
return $original->getTitle() == $new->getTitle();
}
public function getScore() : int
{
return 20;
}
public function getApplicableOutput() : string
{
return 'Element has same title attribute as original -> ' . $this->getScore() . ' points.';
}
}
class CssClassComparator implements HtmlComparator
{
public function applies(Element $original, Element $new) : bool
{
return $original->getClass() == $new->getClass();
}
public function getScore() : int
{
return 10;
}
public function getApplicableOutput() : string
{
return 'Element has same class attribute as original -> ' . $this->getScore() . ' points.';
}
}
class RelComparator implements HtmlComparator
{
public function applies(Element $original, Element $new) : bool
{
return $original->getRel() == $new->getRel();
}
public function getScore() : int
{
return 5;
}
public function getApplicableOutput() : string
{
return 'Element has same rel attribute as original -> ' . $this->getScore() . ' points.';
}
}
class SameElementFinder
{
const MIN_SCORE = 20;
private function formatPath($path)
{
return str_replace('/', ' < ', substr($path, 1));
}
public function find($originalFile, $diffFile, $originalElementId)
{
$dom = new DOMDocument('1.0');
@$dom->loadHTMLFile($originalFile);
$originalElement = new Element($dom->getElementById($originalElementId));
@$dom->loadHTMLFile($diffFile);
$domElementWithSameIdAsOriginal = $dom->getElementById($originalElementId);
if (! empty($domElementWithSameIdAsOriginal)) {
echo 'Found element with same id as original.' . PHP_EOL;
return $this->formatPath($domElementWithSameIdAsOriginal->getNodePath());
}
echo 'Could not find element with same id as original.' . PHP_EOL;
$domElementsByTag = $dom->getElementsByTagName($originalElement->getTag());
echo 'Found ' . count($domElementsByTag) . ' elements for tag ' . $originalElement->getTag() . '.' . PHP_EOL;
$maxScore = 0;
$bestMatch = null;
$comparatorImplementations = array_filter(
get_declared_classes(),
function ($className) {
return in_array('HtmlComparator', class_implements($className));
}
);
foreach ($domElementsByTag as $i => $domElement) {
$element = new Element($domElement);
echo 'Element ' . ($i + 1) . PHP_EOL;
$score = 0;
foreach ($comparatorImplementations as $comparatorImplementation) {
$comparator = new $comparatorImplementation;
if ($comparator->applies($originalElement, $element)) {
$score += $comparator->getScore();
echo $comparator->getApplicableOutput() . PHP_EOL;
}
}
echo 'Total score: ' . $score . PHP_EOL;
if ($score > $maxScore) {
$maxScore = $score;
$bestMatch = $domElement->getNodePath();
echo 'Element is best match so far!' . PHP_EOL;
}
echo '********************' . PHP_EOL;
}
return ($maxScore >= self::MIN_SCORE) ? $this->formatPath($bestMatch) . '.' : 'No matching element found.';
}
}
$elementId = isset($argv[3]) ? $argv[3] : 'make-everything-ok-button';
$finder = new SameElementFinder;
$result = $finder->find($argv[1], $argv[2], $elementId);
echo 'Result: ' . $result . PHP_EOL;