Skip to content

Commit

Permalink
modified the conversion method for json to csv to make it healthier w…
Browse files Browse the repository at this point in the history
…here there may exist different properties for each object.
  • Loading branch information
ozdemirburak committed Oct 1, 2018
1 parent d567361 commit 644aba8
Show file tree
Hide file tree
Showing 10 changed files with 101 additions and 58 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ $ composer test

## Known Issues

Currently, it is assumed that each object shares the same properties while converting JSON to CSV. So if one object has a property that the other one does not have, then it will be a major problem.
Currently, there are not any issues that are known.

## Contributing

Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
}
],
"require": {
"php" : "~7.0"
"php" : "~7.0",
"ext-json": "*"
},
"require-dev": {
"phpunit/phpunit" : "~5.0|~6.0"
Expand Down
13 changes: 7 additions & 6 deletions src/AbstractFile.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ public function __construct($filepath)
*/
public function convertAndDownload($filename = null, $exit = true)
{
header('Content-disposition: attachment; filename=' . ($filename ?? $this->filename) . '.' . $this->conversion['extension']);
$filename = $filename ?? $this->filename;
header('Content-disposition: attachment; filename=' . $filename . '.' . $this->conversion['extension']);
header('Content-type: ' . $this->conversion['type']);
echo $this->convert();
if ($exit === true) {
Expand All @@ -48,23 +49,23 @@ public function convertAndDownload($filename = null, $exit = true)
*
* @return bool|int
*/
public function convertAndSave($path) : int
public function convertAndSave($path): int
{
return file_put_contents($path, $this->convert());
}

/**
* @return string
*/
public function getData() : string
public function getData(): string
{
return $this->data;
}

/**
* @return string
*/
public function getFilename() : string
public function getFilename(): string
{
return $this->filename;
}
Expand All @@ -75,7 +76,7 @@ public function getFilename() : string
*
* @return array
*/
public function setConversionKey($key, $value) : array
public function setConversionKey($key, $value): array
{
$this->conversion[$key] = $value;
return $this->conversion;
Expand All @@ -84,5 +85,5 @@ public function setConversionKey($key, $value) : array
/**
* @return string
*/
abstract public function convert() : string;
abstract public function convert(): string;
}
28 changes: 24 additions & 4 deletions src/File/Csv.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,37 @@ class Csv extends AbstractFile
/**
* @var array
*/
protected $conversion = ['extension' => 'json', 'type' => 'application/json', 'options' => 0, 'delimiter' => ',', 'enclosure' => '"', 'escape' => '\\'];
protected $conversion = [
'extension' => 'json',
'type' => 'application/json',
'options' => 0,
'delimiter' => ',',
'enclosure' => '"',
'escape' => '\\'
];

/**
* @return string
*/
public function convert() : string
public function convert(): string
{
$data = explode("\n", $this->data);
$keys = str_getcsv(array_shift($data), $this->conversion['delimiter'], $this->conversion['enclosure'], $this->conversion['escape']);
$keys = str_getcsv(
array_shift($data),
$this->conversion['delimiter'],
$this->conversion['enclosure'],
$this->conversion['escape']
);
return json_encode(array_map(function ($line) use ($keys) {
return array_combine($keys, str_getcsv($line, $this->conversion['delimiter'], $this->conversion['enclosure'], $this->conversion['escape']));
return array_combine(
$keys,
str_getcsv(
$line,
$this->conversion['delimiter'],
$this->conversion['enclosure'],
$this->conversion['escape']
)
);
}, $data), $this->conversion['options']);
}
}
73 changes: 45 additions & 28 deletions src/File/Json.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,48 +9,54 @@ class Json extends AbstractFile
/**
* @var array
*/
protected $conversion = ['extension' => 'csv', 'type' => 'text/csv', 'delimiter' => ',', 'enclosure' => '"', 'escape' => '\\'];
protected $conversion = [
'extension' => 'csv',
'type' => 'text/csv',
'delimiter' => ',',
'enclosure' => '"',
'escape' => '\\',
'null' => null
];

/**
* @return string
*/
public function convert() : string
public function convert(): string
{
$data_decoded = json_decode($this->data, true);
$data_flattened = array_map(function ($d) {
$flattened = array_map(function ($d) {
return $this->flatten($d);
}, $data_decoded);

$keys = [];
foreach ($data_flattened as $entry_flattened) {
foreach ($entry_flattened as $key => $value) {
$keys[$key] = true;
}
}

$data_unified = [];
foreach ($data_flattened as $entry_flattened) {
$entry_unified = [];
foreach ($keys as $key => $foo) {
$entry_unified[$key] = array_key_exists($key, $entry_flattened) ? $entry_flattened[$key] : null;
}
$data_unified[] = $entry_unified;
}

return $this->toCsvString($data_unified);
}, json_decode($this->data, true));
// create an array with all of the keys where each has a null value
$default = $this->getArrayOfNulls($flattened);
// merge default with the actual data so that non existent keys will have null values
return $this->toCsvString(array_map(function ($d) use ($default) {
return array_merge($default, $d);
}, $flattened));
}

/**
* @param array $data
*
* @return string
*/
protected function toCsvString(array $data) : string
protected function toCsvString(array $data): string
{
$f = fopen('php://temp', 'w');
fputcsv($f, array_keys(current($data)), $this->conversion['delimiter'], $this->conversion['enclosure'], $this->conversion['escape']);
$f = fopen('php://temp', 'wb');
fputcsv(
$f,
array_keys(current($data)),
$this->conversion['delimiter'],
$this->conversion['enclosure'],
$this->conversion['escape']
);
foreach ($data as $row) {
fputcsv($f, $row, $this->conversion['delimiter'], $this->conversion['enclosure'], $this->conversion['escape']);
fputcsv(
$f,
$row,
$this->conversion['delimiter'],
$this->conversion['enclosure'],
$this->conversion['escape']
);
}
rewind($f);
$csv = stream_get_contents($f);
Expand All @@ -65,7 +71,7 @@ protected function toCsvString(array $data) : string
*
* @return array
*/
protected function flatten(array $array = [], $prefix = '', array $result = []) : array
protected function flatten(array $array = [], $prefix = '', array $result = []): array
{
foreach ($array as $key => $value) {
if (\is_array($value)) {
Expand All @@ -76,4 +82,15 @@ protected function flatten(array $array = [], $prefix = '', array $result = [])
}
return $result;
}

/**
* @param $flattened
*
* @return array
*/
protected function getArrayOfNulls($flattened): array
{
$keys = array_keys(array_merge(...$flattened));
return array_fill_keys($keys, $this->conversion['null']);
}
}
9 changes: 4 additions & 5 deletions tests/JsonTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,13 @@ public function testConversionAndDownload()
/**
* @group json-conversion-test
*/
public function testConversionDynamicFormat()
public function testMixedProperties()
{
$json = new Json(__DIR__ . '/data/dynamicFormat.json');
$result = ($json->convert());
$this->assertEquals(file_get_contents(__DIR__ . '/data/dynamicFormatResult.csv'), $result);
$json = new Json(__DIR__ . '/data/mixed-properties.json');
$result = $json->convert();
$this->assertStringEqualsFile(__DIR__ . '/data/mixed-properties.csv', $result);
}


/**
* @return \OzdemirBurak\JsonCsv\File\Json
*/
Expand Down
10 changes: 0 additions & 10 deletions tests/data/dynamicFormat.json

This file was deleted.

3 changes: 0 additions & 3 deletions tests/data/dynamicFormatResult.csv

This file was deleted.

3 changes: 3 additions & 0 deletions tests/data/mixed-properties.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
a,b,c_d,c_e,c,d
0,1,1,2,,
3,,,,4,5
15 changes: 15 additions & 0 deletions tests/data/mixed-properties.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[
{
"a": 0,
"b": 1,
"c": {
"d": 1,
"e": 2
}
},
{
"a": 3,
"c": 4,
"d": 5
}
]

0 comments on commit 644aba8

Please sign in to comment.