diff --git a/src/Csv.php b/src/Csv.php index fb4dad4..a85f819 100644 --- a/src/Csv.php +++ b/src/Csv.php @@ -15,7 +15,7 @@ public function __construct(string $filePath) ); } - public static function make(array $data) + public static function write(array $data) { return new CsvWriter($data); } diff --git a/src/CsvWriter.php b/src/CsvWriter.php index 564b941..f4702b6 100644 --- a/src/CsvWriter.php +++ b/src/CsvWriter.php @@ -13,21 +13,26 @@ public function __construct(array $data) $this->data = $data; } - public function toFile(string $filePath) + public function toFile(string $filePath, $append = false) { - $handle = fopen($filePath, 'w'); + $fileMode = $append ? 'a' : 'w'; + $handle = fopen($filePath, $fileMode); + if ($handle === false) { + throw new \Exception("Could not open file: $filePath"); + } + + if ($append === true) { + $headers = fgetcsv(fopen($filePath, 'r')); + $this->headers = $headers; + } - if ($this->headers !== []) { + if ($this->headers !== [] && $append === false) { fputcsv($handle, $this->headers); } foreach ($this->data as $row) { if ($this->headers !== []) { - // if the keys of the row are strings, then we need to merge the headers with the row - // so that the keys are in the same order as the headers - if (array_keys($row) !== range(0, count($row) - 1)) { - $row = array_merge(array_flip($this->headers), $row); - } + $row = $this->normalizeRowWithHeaders($row); } fputcsv($handle, $row); @@ -43,4 +48,15 @@ public function withHeaders(array $headers) return $this; } + + protected function normalizeRowWithHeaders($row) + { + // if the keys of the row are strings, then we need to merge the headers with the row + // so that the keys are in the same order as the headers + if (array_keys($row) !== range(0, count($row) - 1)) { + return array_merge(array_flip($this->headers), $row); + } + + return $row; + } } diff --git a/tests/Fixtures/data_write.csv b/tests/Fixtures/data_write.csv index 997d2bc..3e38485 100644 --- a/tests/Fixtures/data_write.csv +++ b/tests/Fixtures/data_write.csv @@ -1,2 +1,3 @@ Col1,Col2,Col3 Foo,Bar,Baz +Foo2,Bar2,Baz2 diff --git a/tests/Unit/CsvWriteTest.php b/tests/Unit/CsvWriteTest.php index 55c7f70..f3b71a4 100644 --- a/tests/Unit/CsvWriteTest.php +++ b/tests/Unit/CsvWriteTest.php @@ -9,7 +9,7 @@ 'Baz', ]]; - $file = Csv::make($data) + $file = Csv::write($data) ->toFile(__DIR__.'/../Fixtures/data_write.csv'); expect(file_get_contents(__DIR__.'/../Fixtures/data_write.csv')) @@ -25,7 +25,7 @@ ], ]; - $file = Csv::make($data) + $file = Csv::write($data) ->withHeaders(['Col1', 'Col2', 'Col3']) ->toFile(__DIR__.'/../Fixtures/data_write.csv'); @@ -47,13 +47,13 @@ ], ]; - $file = Csv::make($data) + $file = Csv::write($data) ->withHeaders(['Col1', 'Col2', 'Col3']) ->toFile(__DIR__.'/../Fixtures/data_write.csv'); $foo = file_get_contents(__DIR__.'/../Fixtures/data_write.csv'); - expect(file_get_contents(__DIR__.'/../Fixtures/data_write.csv')) + expect($foo) ->toBe( 'Col1,Col2,Col3'.PHP_EOL. 'Foo,Bar,Baz'.PHP_EOL @@ -68,25 +68,64 @@ ], ]; - $file = Csv::make($data) + $file = Csv::write($data) ->withHeaders(['Col1', 'Col2', 'Col3']) ->toFile(__DIR__.'/../Fixtures/data_write.csv'); + expect(file_get_contents(__DIR__.'/../Fixtures/data_write.csv')) + ->toBe( + 'Col1,Col2,Col3'.PHP_EOL. + 'Foo,Bar,Baz'.PHP_EOL + ); $data = [[ 'Foo', 'Bar', 'Baz', - ], + ]]; + $file = Csv::write($data) + ->toFile(__DIR__.'/../Fixtures/data_write.csv', true); + + expect(file_get_contents(__DIR__.'/../Fixtures/data_write.csv')) + ->toBe( + 'Col1,Col2,Col3'.PHP_EOL. + 'Foo,Bar,Baz'.PHP_EOL. + 'Foo,Bar,Baz'.PHP_EOL + ); +}); + +test('It appends assoc data to a file in the right order', function () { + $data = [ + [ + 'Col2' => 'Bar', + 'Col1' => 'Foo', + 'Col3' => 'Baz', + ], ]; - $file = Csv::make($data) + $file = Csv::write($data) ->withHeaders(['Col1', 'Col2', 'Col3']) - ->toFile(__DIR__.'/../Fixtures/data_write.csv', 'a'); + ->toFile(__DIR__.'/../Fixtures/data_write.csv'); expect(file_get_contents(__DIR__.'/../Fixtures/data_write.csv')) ->toBe( 'Col1,Col2,Col3'.PHP_EOL. - 'Foo,Bar,Baz'.PHP_EOL. 'Foo,Bar,Baz'.PHP_EOL ); + $data = [ + [ + 'Col2' => 'Bar2', + 'Col1' => 'Foo2', + 'Col3' => 'Baz2', + ], + ]; + $file = Csv::write($data) + ->withHeaders(['Col1', 'Col2', 'Col3']) + ->toFile(__DIR__.'/../Fixtures/data_write.csv', true); + + expect(file_get_contents(__DIR__.'/../Fixtures/data_write.csv')) + ->toBe( + 'Col1,Col2,Col3'.PHP_EOL. + 'Foo,Bar,Baz'.PHP_EOL. + 'Foo2,Bar2,Baz2'.PHP_EOL + ); });