Passed
Pull Request — master (#6)
by
unknown
02:26
created

XMLParser   A

Complexity

Total Complexity 39

Size/Duplication

Total Lines 157
Duplicated Lines 0 %

Test Coverage

Coverage 91.67%

Importance

Changes 0
Metric Value
eloc 75
dl 0
loc 157
ccs 77
cts 84
cp 0.9167
rs 9.28
c 0
b 0
f 0
wmc 39

13 Methods

Rating   Name   Duplication   Size   Complexity  
A shouldBeSkipped() 0 7 2
B chunk() 0 32 7
A isElement() 0 5 3
B extractElement() 0 27 7
A from() 0 5 1
A each() 0 12 4
A getCurrentElementAttributes() 0 8 3
A stop() 0 4 2
A withoutSkippingFirstElement() 0 4 1
A searchElement() 0 4 3
A isEndElement() 0 5 3
A start() 0 6 1
A isValue() 0 2 2
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\Exceptions\StopParseException;
14
use Rodenastyle\StreamParser\StreamParserInterface;
15
use Tightenco\Collect\Support\Collection;
16
use XMLReader;
17
18
19
class XMLParser implements StreamParserInterface
20
{
21
	protected $reader,$source;
22
23
	protected $skipFirstElement = true;
24
25 7
	public function from(String $source): StreamParserInterface
26
	{
27 7
		$this->source = $source;
28
29 7
		return $this;
30
	}
31
32
	public function withoutSkippingFirstElement(){
33
		$this->skipFirstElement = false;
34
35
		return $this;
36
	}
37
38 7
	public function each(callable $function)
39
	{
40 7
		$this->start();
41
		try {
42 7
			while($this->reader->read()){
43 7
				if($this->searchElement($function) === false) {
44 1
					break;
45
				}
46
			}
47 1
		} catch (StopParseException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
48 7
		} finally {
49 7
			$this->stop();
50
		}
51 7
	}
52
53 7
	public function chunk($count, callable $function)
54
	{
55 7
		if($count <= 0) {
56
			return;
57
		}
58
59 7
		$this->start();
60
		try {
61 7
			$chunk = new Collection();
62
63 7
			while($this->reader->read()){
64 7
				$this->searchElement(function($item) use (&$chunk) {
65 7
					$chunk->push($item);
66 7
				});
67
68 7
				if($chunk->count() >= $count) {
69 7
					$stop = $function($chunk) === false;
70
71 7
					$chunk = new Collection();
72
73 7
					if($stop) {
74 1
						break;
75
					}
76
				}
77
			}
78
79 7
			if($chunk->count() > 0) {
80 7
				$function($chunk);
81
			}
82 1
		} catch (StopParseException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
83 7
		} finally {
84 7
			$this->stop();
85
		}
86 7
	}
87
88 7
	private function searchElement(callable $function)
89
	{
90 7
		if($this->isElement() && ! $this->shouldBeSkipped()){
91 7
			return $function($this->extractElement($this->reader->name));
92
		}
93 7
	}
94
95 7
	private function extractElement(String $elementName, $couldBeAnElementsList = false)
96
	{
97 7
		$elementCollection = (new Collection())->merge($this->getCurrentElementAttributes());
98
99 7
		while($this->reader->read()){
100 7
			if($this->isEndElement($elementName)){
101 7
				break;
102
			}
103 7
			if($this->isValue()){
104 7
				if($elementCollection->isEmpty()){
105 7
					return trim($this->reader->value);
106
				} else {
107 7
					return $elementCollection->put($elementName, trim($this->reader->value));
108
				}
109
			}
110 7
			if($this->isElement()){
111 7
				if($couldBeAnElementsList){
112 7
					$foundElementName = $this->reader->name;
113 7
					$elementCollection->push(new Collection($this->extractElement($foundElementName)));
114
				} else {
115 7
					$foundElementName = $this->reader->name;
116 7
					$elementCollection->put($foundElementName, $this->extractElement($foundElementName, true));
117
				}
118
			}
119
		}
120
121 7
		return $elementCollection;
122
	}
123
124 7
	private function getCurrentElementAttributes(){
125 7
		$attributes = new Collection();
126 7
		if($this->reader->hasAttributes)  {
127 7
			while($this->reader->moveToNextAttribute()) {
128 7
				$attributes->put($this->reader->name, $this->reader->value);
129
			}
130
		}
131 7
		return $attributes;
132
	}
133
134 7
	private function start()
135
	{
136 7
		$this->reader = new XMLReader();
137 7
		$this->reader->open($this->source);
138
139 7
		return $this;
140
	}
141
142 7
	private function stop()
143
	{
144 7
		if( ! $this->reader->close()){
145
			throw new IncompleteParseException();
146
		}
147 7
	}
148
149 7
	private function shouldBeSkipped(){
150 7
		if($this->skipFirstElement){
151 7
			$this->skipFirstElement = false;
152 7
			return true;
153
		}
154
155 7
		return false;
156
	}
157
158 7
	private function isElement(String $elementName = null){
159 7
		if($elementName){
160
			return $this->reader->nodeType == XMLReader::ELEMENT && $this->reader->name === $elementName;
161
		} else {
162 7
			return $this->reader->nodeType == XMLReader::ELEMENT;
163
		}
164
	}
165
166 7
	private function isEndElement(String $elementName = null){
167 7
		if($elementName){
168 7
			return $this->reader->nodeType == XMLReader::END_ELEMENT && $this->reader->name === $elementName;
169
		} else {
170
			return $this->reader->nodeType == XMLReader::END_ELEMENT;
171
		}
172
	}
173
174 7
	private function isValue(){
175 7
		return $this->reader->nodeType == XMLReader::TEXT || $this->reader->nodeType === XMLReader::CDATA;
176
	}
177
}
178