Passed
Pull Request — master (#17)
by Sergio
03:28 queued 14s
created

XMLParser::start()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 0
dl 0
loc 6
ccs 4
cts 4
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: sergio.rodenas
5
 * Date: 12/5/18
6
 * Time: 0:09
7
 */
8
9
namespace Rodenastyle\StreamParser\Parsers;
10
11
12
use Rodenastyle\StreamParser\Exceptions\IncompleteParseException;
13
use Rodenastyle\StreamParser\StreamParserInterface;
14
use Tightenco\Collect\Support\Collection;
15
use XMLReader;
16
17
18
class XMLParser implements StreamParserInterface
19
{
20
	protected $reader,$source;
21
22
	protected $skipFirstElement = true;
23
24 7
	public function from(String $source): StreamParserInterface
25
	{
26 7
		$this->source = $source;
27
28 7
		return $this;
29
	}
30
31
	public function withoutSkippingFirstElement(){
32
		$this->skipFirstElement = false;
33
34
		return $this;
35
	}
36
37 7
	public function each(callable $function)
38
	{
39 7
		$this->start();
40 7
		while($this->reader->read()){
41 7
			$this->searchElement($function);
42
		}
43 7
		$this->stop();
44 7
	}
45
46 7
	private function searchElement(callable $function)
47
	{
48 7
		if($this->isElement() && ! $this->shouldBeSkipped()){
49 7
			$function($this->extractElement($this->reader->name));
50
		}
51 7
	}
52
53 7
	private function extractElement(String $elementName, $couldBeAnElementsList = false)
54
	{
55 7
		$elementCollection = (new Collection())->merge($this->getCurrentElementAttributes());
56
57 7
		if($this->isEmptyElement($elementName)) {
58 7
			return $elementCollection;
59
		}
60
61 7
		while($this->reader->read()) {
62 7
			if($this->isEndElement($elementName)) {
63 7
				break;
64
			}
65 7
			if($this->isValue()) {
66 7
				if($elementCollection->isEmpty()) {
67 7
					return trim($this->reader->value);
68
				} else {
69 7
					return $elementCollection->put($elementName, trim($this->reader->value));
70
				}
71
			}
72 7
			if($this->isElement()) {
73 7
				if($couldBeAnElementsList) {
74 7
					$foundElementName = $this->reader->name;
75 7
					$elementCollection->push(new Collection($this->extractElement($foundElementName)));
76
				} else {
77 7
					$foundElementName = $this->reader->name;
78 7
					$elementCollection->put($foundElementName, $this->extractElement($foundElementName, true));
79
				}
80
			}
81
		}
82
83 7
		return $elementCollection;
84
	}
85
86 7
	private function getCurrentElementAttributes(){
87 7
		$attributes = new Collection();
88 7
		if($this->reader->hasAttributes)  {
89 7
			while($this->reader->moveToNextAttribute()) {
90 7
				$attributes->put($this->reader->name, $this->reader->value);
91
			}
92
		}
93 7
		return $attributes;
94
	}
95
96 7
	private function start()
97
	{
98 7
		$this->reader = new XMLReader();
99 7
		$this->reader->open($this->source);
100
101 7
		return $this;
102
	}
103
104 7
	private function stop()
105
	{
106 7
		if( ! $this->reader->close()){
107
			throw new IncompleteParseException();
108
		}
109 7
	}
110
111 7
	private function shouldBeSkipped(){
112 7
		if($this->skipFirstElement){
113 7
			$this->skipFirstElement = false;
114 7
			return true;
115
		}
116
117 7
		return false;
118
	}
119
120 7
	private function isElement(String $elementName = null){
121 7
		if($elementName){
122
			return $this->reader->nodeType == XMLReader::ELEMENT && $this->reader->name === $elementName;
123
		} else {
124 7
			return $this->reader->nodeType == XMLReader::ELEMENT;
125
		}
126
	}
127
128 7
	private function isEndElement(String $elementName = null){
129 7
		if($elementName){
130 7
			return $this->reader->nodeType == XMLReader::END_ELEMENT && $this->reader->name === $elementName;
131
		} else {
132
			return $this->reader->nodeType == XMLReader::END_ELEMENT;
133
		}
134
	}
135
136 7
	private function isValue(){
137 7
		return $this->reader->nodeType == XMLReader::TEXT || $this->reader->nodeType === XMLReader::CDATA;
138
	}
139
140 7
    private function isEmptyElement(String $elementName = null){
141 7
	    if($elementName) {
142 7
		    return $this->reader->isEmptyElement && $this->reader->name === $elementName;
143
	    } else {
144
		    return false;
145
	    }
146
    }
147
}
148