CSVParser::getCurrentLineAsCollection()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 1

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 6
c 2
b 0
f 0
nc 1
nop 0
dl 0
loc 9
ccs 7
cts 7
cp 1
crap 1
rs 10
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: sergio.rodenas
5
 * Date: 15/5/18
6
 * Time: 18:59
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
16
class CSVParser implements StreamParserInterface
17
{
18
	protected $reader, $source, $headers, $currentLine;
19
20
	public static $delimiters = [",", ";"];
21
	public static $fieldDelimiter = ",";
22
	public static $skipsEmptyLines = true;
23
24 10
	public function from(String $source): StreamParserInterface
25
	{
26 10
		$this->source = $source;
27
28 10
		return $this;
29
	}
30
31 10
	public function each(callable $function)
32
	{
33 10
		$this->start();
34 10
		while($this->read()){
35 10
			if($this->currentLineIsValid()){
36 10
				$function($this->getCurrentLineAsCollection());
37
			}
38
		}
39 10
		$this->close();
40 10
	}
41
42 10
	private function start()
43
	{
44 10
		$this->reader = fopen($this->source, 'r');
45
46 10
		$this->read();
47 10
		$this->headers = $this->currentLine;
48
49 10
		return $this;
50
	}
51
52 10
	private function close(){
53 10
		if( ! fclose($this->reader)){
54
			throw new IncompleteParseException();
55
		}
56 10
	}
57
58 10
	private function read(): bool{
59 10
		$this->currentLine = new Collection(fgetcsv($this->reader, null, static::$fieldDelimiter));
60
61
		//EOF detection
62 10
		return $this->currentLine->first() !== false;
63
	}
64
65 10
	private function currentLineIsValid(): bool{
66 10
		if(static::$skipsEmptyLines){
67 8
			return ! $this->currentLineIsEmpty();
68
		}
69
70 2
		return true;
71
	}
72
73
	private function currentLineIsEmpty(){
74 8
		return $this->currentLine->reject(function($value){
75 8
			return $this->isEmptyValue($value);
76 8
		})->isEmpty();
77
	}
78
79 10
	private function isEmptyValue($value){
80 10
		return $value === "" || $value === null;
81
	}
82
83 10
	private function getCurrentLineAsCollection()
84
	{
85 10
		$headers = $this->headers;
86 10
		$values = $this->formatCurrentLineValues($this->currentLine);
87
88 10
		return $headers->intersectByKeys($this->currentLine)
89 10
			->combine($values->recursive())
90 10
			->reject(function($value){
91 10
				return $this->isEmptyValue($value);
92 10
			});
93
	}
94
95 10
	private function formatCurrentLineValues(Collection $collection){
96 10
		$this->explodeCollectionValues($collection);
97 10
		return $collection;
98
	}
99
100
	private function explodeCollectionValues(Collection $collection){
101
		$collection->transform(function($value){
102 10
			(new Collection(static::$delimiters))->each(function($delimiter) use (&$value){
103 10
				if( ! is_array($value) && strpos($value, $delimiter) !== false){
104 10
					$value = explode($delimiter, $value);
105
				}
106 10
			});
107 10
			if(is_array($value)){
108 10
				return (new Collection($value))->reject(function($value){
109 10
					return $this->isEmptyValue($value);
110 10
				});
111
			} else {
112 10
				return $value;
113
			}
114 10
		});
115 10
	}
116
}
117