XMLParser::stop()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2.1481

Importance

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