Passed
Pull Request — master (#29)
by
unknown
03:43
created

XMLParser   A

Complexity

Total Complexity 36

Size/Duplication

Total Lines 131
Duplicated Lines 0 %

Test Coverage

Coverage 89.86%

Importance

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