Skip to content

Commit d46e83e

Browse files
authored
Merge pull request #27 from keboola/odin-reader-writer
Refactor - split into Reader and Writer classes
2 parents eb77f51 + 3bc11a7 commit d46e83e

File tree

11 files changed

+1298
-1090
lines changed

11 files changed

+1298
-1090
lines changed

README.md

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,25 @@
77

88
The library provides a simple reader and writer for CSV files according to [RFC4180](https://tools.ietf.org/html/rfc4180).
99
The library is licensed under the [MIT](https://github.com/keboola/php-csv/blob/master/LICENSE) license. The library provides
10-
a single `CsvFile` class for both reading and writing CSV files. The class is designed to be **immutable** and minimalistic.
10+
classes `CsvReader` and `CsvWriter` for reading and writing CSV files. The classes are designed to be **immutable**
11+
and minimalistic.
1112

1213
## Usage
1314

1415
### Read CSV
1516

1617
```php
17-
$csvFile = new Keboola\Csv\CsvFile(__DIR__ . '/_data/test-input.csv');
18+
$csvFile = new Keboola\Csv\CsvReader(__DIR__ . '/_data/test-input.csv');
1819
foreach($csvFile as $row) {
1920
var_dump($row);
2021
}
2122
```
2223

2324
#### Skip lines
24-
Skip the first two lines:
25+
Skip the first line:
2526

2627
```php
27-
use Keboola\Csv\CsvFile;
28-
$filename = __DIR__ . '/_data/test-input.csv';
29-
$csvFile = new \Keboola\Csv\CsvFile($fileName, CsvFile::DEFAULT_DELIMITER, CsvFile::DEFAULT_ENCLOSURE, CsvFile::DEFAULT_ENCLOSURE, 2)
28+
$csvFile = new \Keboola\Csv\CsvFile($fileName, CsvFile::DEFAULT_DELIMITER, CsvFile::DEFAULT_ENCLOSURE, CsvFile::DEFAULT_ESCAPED_BY, 1)
3029
foreach($csvFile as $row) {
3130
var_dump($row);
3231
}
@@ -36,21 +35,42 @@ foreach($csvFile as $row) {
3635
### Write CSV
3736

3837
```php
39-
$csvFile = new Keboola\Csv\CsvFile(__DIR__ . '/_data/test-output.csv');
40-
$rows = array(
41-
array(
38+
$csvFile = new Keboola\Csv\CsvWriter(__DIR__ . '/_data/test-output.csv');
39+
$rows = [
40+
[
4241
'col1', 'col2',
43-
),
44-
array(
45-
'line without enclosure', 'second column',
46-
),
47-
);
42+
],
43+
[
44+
'first column', 'second column',
45+
],
46+
];
4847

4948
foreach ($rows as $row) {
5049
$csvFile->writeRow($row);
5150
}
5251
```
5352

53+
### Append to CSV
54+
55+
```php
56+
$fileName = __DIR__ . '/_data/test-output.csv';
57+
$file = fopen($fileName, 'a');
58+
$csvFile = new Keboola\Csv\CsvWriter($file);
59+
$rows = [
60+
[
61+
'col1', 'col2',
62+
],
63+
[
64+
'first column', 'second column',
65+
],
66+
];
67+
68+
foreach ($rows as $row) {
69+
$csvFile->writeRow($row);
70+
}
71+
fclose($file);
72+
```
73+
5474
## Installation
5575

5676
The library is available as [composer package](https://getcomposer.org/doc/00-intro.md#installation-linux-unix-osx).
@@ -69,5 +89,4 @@ composer require keboola/csv
6989
require 'vendor/autoload.php';
7090
```
7191

72-
7392
Read more in [Composer documentation](http://getcomposer.org/doc/01-basic-usage.md)

src/AbstractCsvFile.php

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
<?php
2+
3+
namespace Keboola\Csv;
4+
5+
abstract class AbstractCsvFile
6+
{
7+
const DEFAULT_DELIMITER = ',';
8+
const DEFAULT_ENCLOSURE = '"';
9+
/**
10+
* @var string
11+
*/
12+
protected $fileName;
13+
/**
14+
* @var resource
15+
*/
16+
protected $filePointer;
17+
18+
/**
19+
* @var string
20+
*/
21+
private $delimiter;
22+
23+
/**
24+
* @var string
25+
*/
26+
private $enclosure;
27+
28+
/**
29+
* @return string
30+
*/
31+
public function getDelimiter()
32+
{
33+
return $this->delimiter;
34+
}
35+
36+
/**
37+
* @param string $delimiter
38+
* @throws InvalidArgumentException
39+
*/
40+
protected function setDelimiter($delimiter)
41+
{
42+
$this->validateDelimiter($delimiter);
43+
$this->delimiter = $delimiter;
44+
}
45+
46+
/**
47+
* @param string $delimiter
48+
* @throws InvalidArgumentException
49+
*/
50+
protected function validateDelimiter($delimiter)
51+
{
52+
if (strlen($delimiter) > 1) {
53+
throw new InvalidArgumentException(
54+
"Delimiter must be a single character. " . json_encode($delimiter) . " received",
55+
Exception::INVALID_PARAM
56+
);
57+
}
58+
59+
if (strlen($delimiter) == 0) {
60+
throw new InvalidArgumentException(
61+
"Delimiter cannot be empty.",
62+
Exception::INVALID_PARAM
63+
);
64+
}
65+
}
66+
67+
/**
68+
* @return string
69+
*/
70+
public function getEnclosure()
71+
{
72+
return $this->enclosure;
73+
}
74+
75+
/**
76+
* @param string $enclosure
77+
* @return $this
78+
* @throws InvalidArgumentException
79+
*/
80+
protected function setEnclosure($enclosure)
81+
{
82+
$this->validateEnclosure($enclosure);
83+
$this->enclosure = $enclosure;
84+
return $this;
85+
}
86+
87+
/**
88+
* @param string $enclosure
89+
* @throws InvalidArgumentException
90+
*/
91+
protected function validateEnclosure($enclosure)
92+
{
93+
if (strlen($enclosure) > 1) {
94+
throw new InvalidArgumentException(
95+
"Enclosure must be a single character. " . json_encode($enclosure) . " received",
96+
Exception::INVALID_PARAM
97+
);
98+
}
99+
}
100+
101+
public function __destruct()
102+
{
103+
$this->closeFile();
104+
}
105+
106+
protected function closeFile()
107+
{
108+
if ($this->fileName && is_resource($this->filePointer)) {
109+
fclose($this->filePointer);
110+
}
111+
}
112+
113+
/**
114+
* @param string|resource $file
115+
*/
116+
protected function setFile($file)
117+
{
118+
if (is_string($file)) {
119+
$this->openCsvFile($file);
120+
$this->fileName = $file;
121+
} elseif (is_resource($file)) {
122+
$this->filePointer = $file;
123+
} else {
124+
throw new InvalidArgumentException("Invalid file: " . var_export($file, true));
125+
}
126+
}
127+
128+
abstract protected function openCsvFile($fileName);
129+
130+
/**
131+
* @return resource
132+
*/
133+
protected function getFilePointer()
134+
{
135+
return $this->filePointer;
136+
}
137+
}

0 commit comments

Comments
 (0)