Test Failed
Branch master (a65217)
by Sergio
03:21
created

XMLParser   A

Complexity

Total Complexity 36

Size/Duplication

Total Lines 133
Duplicated Lines 0 %

Test Coverage

Coverage 90%

Importance

Changes 4
Bugs 0 Features 0
Metric Value
eloc 62
c 4
b 0
f 0
dl 0
loc 133
ccs 63
cts 70
cp 0.9
rs 9.52
wmc 36

13 Methods

Rating   Name   Duplication   Size   Complexity  
A from() 0 5 1
A each() 0 7 2
A withoutSkippingFirstElement() 0 4 1
A searchElement() 0 4 3
A shouldBeSkipped() 0 7 2
A isElement() 0 5 3
B extractElement() 0 37 10
A getCurrentElementAttributes() 0 8 3
A stop() 0 4 2
A isEmptyElement() 0 5 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\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 10
	public function from(String $source): StreamParserInterface
25
	{
26 10
		$this->source = $source;
27
28 10
		return $this;
29
	}
30
31
	public function withoutSkippingFirstElement(){
32
		$this->skipFirstElement = false;
33
34
		return $this;
35
	}
36
37 10
	public function each(callable $function)
38
	{
39 10
		$this->start();
40 10
		while($this->reader->read()){
41 10
			$this->searchElement($function);
42
		}
43 10
		$this->stop();
44 10
	}
45
46 10
	private function searchElement(callable $function)
47
	{
48 10
		if($this->isElement() && ! $this->shouldBeSkipped()){
49 10
			$function($this->extractElement($this->reader->name, false, $this->reader->depth), $this->reader->name);
50
		}
51 10
	}
52
53 10
	private function extractElement(String $elementName, $couldBeAnElementsList = false, int $parentDepth, string $foundInEl = null)
54
	{
55 10
		$emptyElement = $this->isEmptyElement($elementName);
56
		
57 10
		$elementCollection = (new Collection())->merge($this->getCurrentElementAttributes());
58
59 10
		if($emptyElement) {
60 10
			return $elementCollection;
61
		}
62
63 10
		while($this->reader->read()) {
64 10
			if($this->isEndElement($elementName) && $this->reader->depth === $parentDepth) {
65 10
				break;
66
			}
67 10
			if($this->isValue()) {
68 10
				if($elementCollection->isEmpty()) {
69 10
				    if (!is_null($foundInEl)) {
70 10
                        return $elementCollection->put($elementName, trim($this->reader->value));
71
                    }
72
73 10
					return trim($this->reader->value);
74
				} else {
75 10
					return $elementCollection->put($elementName, trim($this->reader->value));
76
				}
77
			}
78 10
			if($this->isElement()) {
79 10
				if($couldBeAnElementsList) {
80 10
					$foundElementName = $this->reader->name;
81 10
					$elementCollection->push(new Collection($this->extractElement($foundElementName, false, $this->reader->depth, $elementName)));
82
				} else {
83 10
					$foundElementName = $this->reader->name;
84 10
					$elementCollection->put($foundElementName, $this->extractElement($foundElementName, true, $this->reader->depth));
85
				}
86
			}
87
		}
88
89 10
		return $elementCollection;
90
	}
91
92 10
	private function getCurrentElementAttributes(){
93 10
		$attributes = new Collection();
94 10
		if($this->reader->hasAttributes)  {
95 10
			while($this->reader->moveToNextAttribute()) {
96 10
				$attributes->put($this->reader->name, $this->reader->value);
97
			}
98
		}
99 10
		return $attributes;
100
	}
101
102 10
	private function start()
103
	{
104 10
		$this->reader = new XMLReader();
105 10
		$this->reader->open($this->source);
106
107 10
		return $this;
108
	}
109
110 10
	private function stop()
111
	{
112 10
		if( ! $this->reader->close()){
113
			throw new IncompleteParseException();
114
		}
115 10
	}
116
117 10
	private function shouldBeSkipped(){
118 10
		if($this->skipFirstElement){
119 10
			$this->skipFirstElement = false;
120 10
			return true;
121
		}
122
123 10
		return false;
124
	}
125
126 10
	private function isElement(String $elementName = null){
127 10
		if($elementName){
128
			return $this->reader->nodeType == XMLReader::ELEMENT && $this->reader->name === $elementName;
129
		} else {
130 10
			return $this->reader->nodeType == XMLReader::ELEMENT;
131
		}
132
	}
133
134 10
	private function isEndElement(String $elementName = null){
135 10
		if($elementName){
136 10
			return $this->reader->nodeType == XMLReader::END_ELEMENT && $this->reader->name === $elementName;
137
		} else {
138
			return $this->reader->nodeType == XMLReader::END_ELEMENT;
139
		}
140
	}
141
142 10
	private function isValue(){
143 10
		return $this->reader->nodeType == XMLReader::TEXT || $this->reader->nodeType === XMLReader::CDATA;
144
	}
145
146 10
	private function isEmptyElement(String $elementName = null){
147 10
		if($elementName) {
148 10
			return $this->reader->isEmptyElement && $this->reader->name === $elementName;
149
		} else {
150
			return false;
151
		}
152
	}
153
}
154