Passed
Push — master ( e12105...5602aa )
by Jean Paul
01:50
created

StackOverflowWebPageHandler::processDivBlock()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 5
c 0
b 0
f 0
nc 3
nop 2
dl 0
loc 13
rs 10
1
<?php
2
3
namespace Coco\SourceWatcher\Vendors\StackOverflow;
4
5
use Coco\SourceWatcher\Watcher\Handler\WebPageHandler;
6
use DOMElement;
7
use DOMNamedNodeMap;
8
use DOMNodeList;
9
use DOMXPath;
10
11
/**
12
 * Class StackOverflowWebPageHandler
13
 *
14
 * @package Coco\SourceWatcher\Vendors\StackOverflow
15
 */
16
class StackOverflowWebPageHandler extends WebPageHandler
17
{
18
    private array $results = [];
19
20
    public function getResults () : array
21
    {
22
        return $this->results;
23
    }
24
25
    public function read () : void
26
    {
27
        parent::read();
28
29
        $this->results = [];
30
31
        $finder = new DomXPath( $this->dom );
32
33
        $classname = "listResults";
34
        $listResultsDom = $finder->query( "//*[contains(@class, '$classname')]" ); // DOMNodeList
35
36
        for ( $i = 0; $i < $listResultsDom->count(); $i++ ) {
37
            $this->processListResults( $listResultsDom->item( $i ) );
38
        }
39
    }
40
41
    private function processListResults ( DOMElement $currentDomNode ) : void
42
    {
43
        if ( $currentDomNode->hasChildNodes() ) {
44
            $children = $currentDomNode->childNodes; // DOMNodeList
45
46
            for ( $i = 0; $i < $children->count(); $i++ ) {
47
                $currentChildrenNode = $children->item( $i );
48
49
                if ( $currentChildrenNode instanceof DOMElement ) {
50
                    $this->processChildNodes( $currentChildrenNode );
51
                }
52
            }
53
        }
54
    }
55
56
    private function processChildNodes ( DOMElement $currentChildrenNode ) : void
57
    {
58
        $currentJob = new StackOverflowJob();
59
60
        $currentJob = $this->setBasicAttributes( $currentChildrenNode->attributes, $currentJob );
61
62
        if ( $currentChildrenNode->hasChildNodes() ) {
63
            if ( trim( $currentChildrenNode->nodeValue ) == "You might be interested in these jobs:" ) {
64
                echo "Found job separator" . PHP_EOL;
65
            } else {
66
                $extraChildNodes = $currentChildrenNode->childNodes; // DOMNodeList
67
68
                for ( $i = 0; $i < $extraChildNodes->count(); $i++ ) {
69
                    // DOMElement or DOMText
70
                    $currentExtraChildNode = $extraChildNodes->item( $i );
71
72
                    if ( $currentExtraChildNode instanceof DOMElement ) {
73
                        $currentJob = $this->processExtraChildNodes( $currentExtraChildNode, $currentJob );
74
                    }
75
                }
76
            }
77
        }
78
79
        if ( $currentJob->allAttributesDefined() ) {
80
            array_push( $this->results, $currentJob );
81
        } else {
82
            echo "Ignoring job because of missing attributes" . PHP_EOL;
83
        }
84
    }
85
86
    private function setBasicAttributes (
87
        DOMNamedNodeMap $attributes,
88
        StackOverflowJob $stackOverflowJob
89
    ) : StackOverflowJob {
90
        if ( $attributes != null ) {
91
            foreach ( $attributes as $currentAttribute ) {
92
                if ( $currentAttribute->name == "data-jobid" ) {
93
                    $stackOverflowJob->setJobId( $currentAttribute->value );
94
                }
95
96
                if ( $currentAttribute->name == "data-result-id" ) {
97
                    $stackOverflowJob->setResultId( $currentAttribute->value );
98
                }
99
100
                if ( $currentAttribute->name == "data-preview-url" ) {
101
                    $stackOverflowJob->setPreviewUrl( $currentAttribute->value );
102
                }
103
            }
104
        }
105
106
        return $stackOverflowJob;
107
    }
108
109
    private function processExtraChildNodes (
110
        DOMElement $currentExtraChildNode,
111
        StackOverflowJob $stackOverflowJob
112
    ) : StackOverflowJob {
113
        if ( $currentExtraChildNode->hasChildNodes() ) {
114
            $currentExtraChildNodeChildren = $currentExtraChildNode->childNodes; // DOMNodeList
115
116
            $nodeCount = $currentExtraChildNodeChildren->count();
117
118
            if ( $nodeCount >= 6 ) {
119
                for ( $i = 0; $i < $nodeCount; $i++ ) {
120
                    $currentDeepNode = $currentExtraChildNodeChildren->item( $i ); // DOMElement or DOMText
121
122
                    if ( $currentDeepNode instanceof DOMElement ) {
123
                        $stackOverflowJob = $this->processImageDivBlocks( $currentDeepNode, $stackOverflowJob );
124
                    }
125
                }
126
            }
127
        }
128
129
        return $stackOverflowJob;
130
    }
131
132
    private function processImageDivBlocks (
133
        DOMElement $currentDeepNode,
134
        StackOverflowJob $stackOverflowJob
135
    ) : StackOverflowJob {
136
        if ( $currentDeepNode->childNodes->count() == 2 ) {
137
            $stackOverflowJob = $this->processImageBlock( $currentDeepNode->childNodes->item( 1 )->attributes,
138
                $stackOverflowJob );
139
        }
140
141
        if ( $currentDeepNode->tagName == "div" && $currentDeepNode->hasChildNodes() ) {
142
            $stackOverflowJob = $this->processDivBlock( $currentDeepNode->childNodes, $stackOverflowJob );
143
        }
144
145
        return $stackOverflowJob;
146
    }
147
148
    private function processImageBlock (
149
        DOMNamedNodeMap $currentDeepNodeAttributes,
150
        StackOverflowJob $stackOverflowJob
151
    ) : StackOverflowJob {
152
        if ( $currentDeepNodeAttributes != null && sizeof( $currentDeepNodeAttributes ) == 2 ) {
153
            $attr1 = $currentDeepNodeAttributes[0]; // DOMAttr
154
            $attr2 = $currentDeepNodeAttributes[1]; // DOMAttr
155
156
            if ( $attr1->name == "src" ) {
157
                $stackOverflowJob->setLogo( $attr1->value );
158
            }
159
160
            if ( $attr2->name == "src" ) {
161
                $stackOverflowJob->setLogo( $attr2->value );
162
            }
163
        }
164
165
        return $stackOverflowJob;
166
    }
167
168
    private function processDivBlock (
169
        DOMNodeList $currentDeepNodeChildren,
170
        StackOverflowJob $stackOverflowJob
171
    ) : StackOverflowJob {
172
        for ( $i = 0; $i < $currentDeepNodeChildren->count(); $i++ ) {
173
            $currentDeepNodeChildrenElement = $currentDeepNodeChildren->item( $i ); // DOMElement or DOMText
174
175
            if ( $currentDeepNodeChildrenElement instanceof DOMElement ) {
176
                $stackOverflowJob = $this->processH2AndH3Elements( $currentDeepNodeChildrenElement, $stackOverflowJob );
177
            }
178
        }
179
180
        return $stackOverflowJob;
181
    }
182
183
    private function refineCompanyName ( string $companyName ) : string
184
    {
185
        if ( strpos( $companyName, "\r\n" ) !== false ) {
186
            $companyNameParts = explode( "\r\n", $companyName );
187
188
            foreach ( $companyNameParts as $index => $currentCompanyNamePart ) {
189
                $companyNameParts[$index] = trim( $currentCompanyNamePart );
190
            }
191
192
            return implode( " ", $companyNameParts );
193
        } else {
194
            return $companyName;
195
        }
196
    }
197
198
    private function setCompanyAndLocation (
199
        DOMElement $element,
200
        StackOverflowJob $stackOverflowJob
201
    ) : StackOverflowJob {
202
        if ( $element->attributes->count() == 0 ) {
203
            $stackOverflowJob->setCompany( $this->refineCompanyName( trim( $element->nodeValue ) ) );
204
        }
205
206
        if ( $element->attributes->count() == 1 && $element->getAttribute( "class" ) == "fc-black-500" ) {
207
            $stackOverflowJob->setLocation( trim( $element->nodeValue ) );
208
        }
209
210
        return $stackOverflowJob;
211
    }
212
213
    private function processH2AndH3Elements (
214
        DOMElement $currentDeepNodeChildrenElement,
215
        StackOverflowJob $stackOverflowJob
216
    ) : StackOverflowJob {
217
        if ( $currentDeepNodeChildrenElement->tagName == "h2" ) {
218
            $stackOverflowJob->setTitle( trim( $currentDeepNodeChildrenElement->nodeValue ) );
219
        }
220
221
        if ( $currentDeepNodeChildrenElement->tagName == "h3" && $currentDeepNodeChildrenElement->hasChildNodes() ) {
222
            $companyAndLocationDomNodeList = $currentDeepNodeChildrenElement->childNodes; // DOMNodeList
223
224
            for ( $i = 0; $i < $companyAndLocationDomNodeList->count(); $i++ ) {
225
                $currentCompanyAndLocationElement = $companyAndLocationDomNodeList->item( $i ); // DOMElement or DOMText
226
227
                if ( $currentCompanyAndLocationElement instanceof DOMElement && $currentCompanyAndLocationElement->nodeName == "span" ) {
228
                    $this->setCompanyAndLocation( $currentCompanyAndLocationElement );
0 ignored issues
show
Bug introduced by
The call to Coco\SourceWatcher\Vendo...setCompanyAndLocation() has too few arguments starting with stackOverflowJob. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

228
                    $this->/** @scrutinizer ignore-call */ 
229
                           setCompanyAndLocation( $currentCompanyAndLocationElement );

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
229
                }
230
            }
231
        }
232
233
        return $stackOverflowJob;
234
    }
235
}
236