Thanks to visit codestin.com
Credit goes to github.com

Skip to content
This repository was archived by the owner on Apr 14, 2025. It is now read-only.

Commit ac26d47

Browse files
committed
Merge pull request #25 from 2upmedia/master
- dropped SKIP_EMPTY and READ_AHEAD due to strange behavior when using c...
2 parents 76f55ff + c90b7cd commit ac26d47

5 files changed

Lines changed: 319 additions & 15 deletions

File tree

lib/EasyCSV/AbstractBase.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public function __construct($path, $mode = 'r+')
1414
touch($path);
1515
}
1616
$this->handle = new \SplFileObject($path, $mode);
17-
$this->handle->setFlags(\SplFileObject::SKIP_EMPTY | \SplFileObject::DROP_NEW_LINE | \SplFileObject::READ_AHEAD);
17+
$this->handle->setFlags(\SplFileObject::DROP_NEW_LINE);
1818
}
1919

2020
public function __destruct()

lib/EasyCSV/Reader.php

Lines changed: 144 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,64 +4,199 @@
44

55
class Reader extends AbstractBase
66
{
7+
/**
8+
* @var bool
9+
*/
710
private $headersInFirstRow = true;
8-
private $headers;
11+
12+
/**
13+
* @var array|bool
14+
*/
15+
private $headers = false;
16+
17+
/**
18+
* @var int
19+
*/
920
private $line;
21+
22+
/**
23+
* @var
24+
*/
1025
private $init;
1126

27+
/**
28+
* @var bool
29+
*/
30+
private $headerLine = false;
31+
32+
/**
33+
* @var bool
34+
*/
35+
private $lastLine = false;
36+
37+
/**
38+
* @param $path
39+
* @param string $mode
40+
* @param bool $headersInFirstRow
41+
*/
1242
public function __construct($path, $mode = 'r+', $headersInFirstRow = true)
1343
{
1444
parent::__construct($path, $mode);
1545
$this->headersInFirstRow = $headersInFirstRow;
1646
$this->line = 0;
1747
}
1848

49+
/**
50+
* @return bool
51+
*/
1952
public function getHeaders()
2053
{
2154
$this->init();
55+
2256
return $this->headers;
2357
}
24-
58+
59+
/**
60+
* @return array|bool
61+
*/
2562
public function getRow()
2663
{
2764
$this->init();
2865
if ($this->handle->eof()) {
2966
return false;
3067
}
3168

32-
if (($row = $this->handle->fgetcsv($this->delimiter, $this->enclosure)) !== false && $row != null) {
69+
$row = $this->handle->fgetcsv($this->delimiter, $this->enclosure);
70+
$isEmpty = $this->rowIsEmpty($row);
71+
72+
if ($row !== false && $row != null && $isEmpty === false) {
3373
$this->line++;
74+
3475
return $this->headers ? array_combine($this->headers, $row) : $row;
76+
} elseif ($isEmpty) {
77+
// empty row, transparently try the next row
78+
return $this->getRow();
3579
} else {
3680
return false;
3781
}
3882
}
3983

84+
/**
85+
* @return array
86+
*/
4087
public function getAll()
4188
{
4289
$data = array();
4390
while ($row = $this->getRow()) {
4491
$data[] = $row;
4592
}
93+
4694
return $data;
4795
}
4896

97+
/**
98+
* @return int zero-based index
99+
*/
49100
public function getLineNumber()
50101
{
51-
return $this->line;
102+
return $this->handle->key();
52103
}
53-
104+
105+
/**
106+
* @return int zero-based index
107+
*/
108+
public function getLastLineNumber()
109+
{
110+
if ($this->lastLine !== false) {
111+
return $this->lastLine;
112+
}
113+
114+
$this->handle->seek($this->handle->getSize());
115+
$lastLine = $this->handle->key();
116+
117+
$this->handle->rewind();
118+
119+
return $this->lastLine = $lastLine;
120+
}
121+
122+
/**
123+
* @return array
124+
*/
125+
public function getCurrentRow()
126+
{
127+
return str_getcsv($this->handle->current(), $this->delimiter, $this->enclosure);
128+
}
129+
130+
/**
131+
* @param $lineNumber zero-based index
132+
*/
133+
public function advanceTo($lineNumber)
134+
{
135+
if ($this->headerLine > $lineNumber) {
136+
throw new \LogicException("Line Number $lineNumber is before the header line that was set");
137+
} elseif ($this->headerLine === $lineNumber) {
138+
throw new \LogicException("Line Number $lineNumber is equal to the header line that was set");
139+
}
140+
141+
$this->line = $lineNumber;
142+
143+
$this->handle->seek($lineNumber);
144+
}
145+
146+
/**
147+
* @param $lineNumber zero-based index
148+
*/
149+
public function setHeaderLine($lineNumber)
150+
{
151+
if ($lineNumber !== 0) {
152+
$this->headersInFirstRow = false;
153+
} else {
154+
return false;
155+
}
156+
157+
$this->headerLine = $lineNumber;
158+
159+
// seek to line before headers
160+
$this->handle->seek($lineNumber);
161+
162+
// get headers
163+
$this->headers = $this->getCurrentRow();
164+
}
165+
54166
protected function init()
55167
{
56168
if (true === $this->init) {
57169
return;
58170
}
59-
$this->init = true;
60-
$this->headers = $this->headersInFirstRow === true ? $this->getRow() : false;
171+
$this->init = true;
172+
173+
if ($this->headersInFirstRow === true) {
174+
$this->handle->rewind();
175+
176+
$this->headers = $this->getRow();
177+
}
61178
}
62179

63-
protected function incrementLine()
180+
/**
181+
* @param $row
182+
* @return bool
183+
*/
184+
protected function rowIsEmpty($row)
64185
{
65-
$this->line++;
186+
$emptyRow = ($row === array(null));
187+
$emptyRowWithDelimiters = (array_filter($row) === array());
188+
$isEmpty = false;
189+
190+
if ($emptyRow) {
191+
$isEmpty = true;
192+
193+
return $isEmpty;
194+
} elseif ($emptyRowWithDelimiters) {
195+
$isEmpty = true;
196+
197+
return $isEmpty;
198+
}
199+
200+
return $isEmpty;
66201
}
67202
}

tests/EasyCSV/Tests/ReaderTest.php

Lines changed: 152 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,46 @@
66

77
class ReaderTest extends \PHPUnit_Framework_TestCase
88
{
9+
protected $headerValues = array( "column1", "column2", "column3" );
10+
protected $expectedRows = array (
11+
0 =>
12+
array (
13+
'column1' => '1column2value',
14+
'column2' => '1column3value',
15+
'column3' => '1column4value',
16+
),
17+
1 =>
18+
array (
19+
'column1' => '2column2value',
20+
'column2' => '2column3value',
21+
'column3' => '2column4value',
22+
),
23+
2 =>
24+
array (
25+
'column1' => '3column2value',
26+
'column2' => '3column3value',
27+
'column3' => '3column4value',
28+
),
29+
3 =>
30+
array (
31+
'column1' => '4column2value',
32+
'column2' => '4column3value',
33+
'column3' => '4column4value',
34+
),
35+
4 =>
36+
array (
37+
'column1' => '5column2value',
38+
'column2' => '5column3value',
39+
'column3' => '5column4value',
40+
),
41+
);
42+
943
/**
1044
* @dataProvider getReaders
1145
*/
1246
public function testOneAtAtime(Reader $reader)
1347
{
14-
while($row = $reader->getRow()) {
48+
while ($row = $reader->getRow()) {
1549
$this->assertTrue(is_array($row));
1650
$this->assertEquals(3, count($row));
1751
}
@@ -30,15 +64,128 @@ public function testGetAll(Reader $reader)
3064
*/
3165
public function testGetHeaders(Reader $reader)
3266
{
33-
$this->assertEquals(array("column1", "column2", "column3"), $reader->getHeaders());
67+
$this->assertEquals( $this->headerValues, $reader->getHeaders());
68+
}
69+
70+
/**
71+
* @dataProvider getReaders
72+
*/
73+
public function testAdvanceto(Reader $reader)
74+
{
75+
$reader->advanceTo( 3 );
76+
77+
$this->assertEquals( 3, $reader->getLineNumber() );
78+
79+
$reader->advanceTo( 0 );
80+
81+
$row = array
82+
(
83+
'column1' => '1column2value',
84+
'column2' => '1column3value',
85+
'column3' => '1column4value',
86+
);
87+
88+
$actualRow = $reader->getRow();
89+
$this->assertEquals( $row, $actualRow );
90+
91+
$reader->advanceTo( 3 );
92+
93+
$row = array
94+
(
95+
'column1' => '4column2value',
96+
'column2' => '4column3value',
97+
'column3' => '4column4value',
98+
);
99+
100+
$this->assertEquals( $row, $reader->getRow() );
101+
}
102+
103+
/**
104+
* @dataProvider getReadersNoHeadersFirstRow
105+
*/
106+
public function testAdvanceToNoHeadersFirstRow(Reader $reader)
107+
{
108+
$row = array (
109+
0 => 'Some Meta Data',
110+
1 => '',
111+
2 => '',
112+
);
113+
114+
$actualRow = $reader->getRow();
115+
$this->assertEquals( $row, $actualRow );
116+
117+
// give it the ol' one-two-switcharoo
118+
$reader->advanceTo(3);
119+
$reader->getRow();
120+
$reader->advanceTo(0);
121+
122+
$this->assertEquals( $row, $reader->getRow() );
34123
}
35-
124+
125+
/**
126+
* @dataProvider getReaders
127+
*/
128+
public function testSetHeaderLine(Reader $reader)
129+
{
130+
$headers = $this->headerValues;
131+
132+
$this->assertEquals( $headers, $reader->getHeaders() );
133+
134+
$reader->setHeaderLine(0);
135+
136+
$this->assertEquals( $headers, $reader->getHeaders() );
137+
}
138+
139+
/**
140+
* @dataProvider getReadersNoHeadersFirstRow
141+
*/
142+
public function testSetHeaderLineNoHeadersFirstRow(Reader $reader)
143+
{
144+
// set headers
145+
$reader->setHeaderLine( 3 );
146+
147+
$this->assertEquals( $this->headerValues, $reader->getHeaders() );
148+
149+
$rows = $reader->getAll();
150+
151+
$this->assertCount(5, $rows);
152+
$this->assertEquals($this->expectedRows, $rows);
153+
}
154+
155+
/**
156+
* @dataProvider getReaders
157+
*/
158+
public function testGetLastLineNumber(Reader $reader)
159+
{
160+
$this->assertEquals( 5, $reader->getLastLineNumber() );
161+
}
162+
163+
/**
164+
* @dataProvider getReadersNoHeadersFirstRow
165+
*/
166+
public function testGetLastLineNumberNoHeadersFirstRow(Reader $reader)
167+
{
168+
$this->assertEquals( 10, $reader->getLastLineNumber() );
169+
}
170+
36171
public function getReaders()
37172
{
38-
$readerSemiColon = new \EasyCSV\Reader(__DIR__ . '/read_sc.csv');
173+
$readerSemiColon = new Reader(__DIR__ . '/read_sc.csv');
39174
$readerSemiColon->setDelimiter(';');
175+
176+
return array(
177+
array(new Reader(__DIR__ . '/read.csv')),
178+
array($readerSemiColon),
179+
);
180+
}
181+
182+
public function getReadersNoHeadersFirstRow()
183+
{
184+
$readerSemiColon = new Reader(__DIR__ . '/read_header_line_sc.csv', 'r+', false );
185+
$readerSemiColon->setDelimiter(';');
186+
40187
return array(
41-
array(new \EasyCSV\Reader(__DIR__ . '/read.csv')),
188+
array(new Reader(__DIR__ . '/read_header_line.csv', 'r+', false )),
42189
array($readerSemiColon),
43190
);
44191
}

0 commit comments

Comments
 (0)