Skip to content

Commit eae0c86

Browse files
committed
added fromString method, improved code
1 parent a24e069 commit eae0c86

File tree

13 files changed

+234
-88
lines changed

13 files changed

+234
-88
lines changed

.travis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
language: php
22

33
php:
4-
- 7.3
5-
- 7.4
64
- 8.0
5+
- 8.1
6+
- 8.2
77

88
sudo: false
99

LICENSE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# The MIT License (MIT)
22

3-
Copyright (c) 2020 Burak Özdemir
3+
Copyright (c) 2023 Burak Özdemir
44

55
> Permission is hereby granted, free of charge, to any person obtaining a copy
66
> of this software and associated documentation files (the "Software"), to deal

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ $json->convertAndSave(__DIR__ . '/above.csv');
3333
$json->convertAndDownload();
3434
```
3535

36+
You can also convert directly from a JSON string using the `fromString` method.
37+
38+
``` php
39+
$csvString = (new Json())->fromString('{"name": "Buddha", "age": 80}')->convert();
40+
```
41+
3642
Assume that the input JSON is something like below.
3743

3844
```json
@@ -82,6 +88,12 @@ $csv->convertAndSave(__DIR__ . '/below.json');
8288
$csv->convertAndDownload();
8389
```
8490

91+
You can also convert directly from a CSV string using the `fromString` method.
92+
93+
``` php
94+
$jsonString = (new Csv())->fromString('[{"name":"Buddha","age":"80"}]')->convert();
95+
```
96+
8597
Assume that the input CSV file is something like below.
8698

8799
**SepalLength**|**SepalWidth**|**PetalLength**|**PetalWidth**|**Name**

src/AbstractFile.php

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,49 +7,85 @@ abstract class AbstractFile
77
/**
88
* @var array
99
*/
10-
protected $conversion;
10+
protected $conversion = [];
1111

1212
/**
1313
* @var string
1414
*/
15-
protected $data;
15+
protected $data = '';
1616

1717
/**
1818
* @var string
1919
*/
20-
protected $filename;
20+
protected $filename = '';
2121

2222
/**
23-
* CsvToJson constructor.
23+
* AbstractFile constructor.
24+
*
25+
* @param string|null $filepath
26+
*/
27+
public function __construct(?string $filepath = null)
28+
{
29+
if ($filepath !== null) {
30+
$this->loadFile($filepath);
31+
}
32+
}
33+
34+
/**
35+
* Load data from a file.
2436
*
2537
* @param string $filepath
2638
*/
27-
public function __construct($filepath)
39+
protected function loadFile(string $filepath): void
2840
{
41+
if (!is_readable($filepath)) {
42+
throw new \RuntimeException("File not readable: $filepath");
43+
}
2944
[$this->filename, $this->data] = [pathinfo($filepath, PATHINFO_FILENAME), file_get_contents($filepath)];
3045
}
3146

3247
/**
33-
* @param null $filename
48+
* @param string|null $filename
3449
* @param bool $exit
3550
*/
36-
public function convertAndDownload($filename = null, $exit = true)
51+
public function convertAndDownload(?string $filename = null, bool $exit = true): void
3752
{
3853
$filename = $filename ?? $this->filename;
39-
header('Content-disposition: attachment; filename=' . $filename . '.' . $this->conversion['extension']);
40-
header('Content-type: ' . $this->conversion['type']);
54+
$this->sendHeaders($filename);
4155
echo $this->convert();
4256
if ($exit === true) {
4357
exit();
4458
}
4559
}
4660

61+
/**
62+
* Send headers for download.
63+
*
64+
* @param string $filename
65+
*/
66+
protected function sendHeaders(string $filename): void
67+
{
68+
header('Content-disposition: attachment; filename=' . $filename . '.' . $this->conversion['extension']);
69+
header('Content-type: ' . $this->conversion['type']);
70+
}
71+
72+
/**
73+
* @param string $dataString
74+
*
75+
* @return $this
76+
*/
77+
public function fromString(string $dataString): AbstractFile
78+
{
79+
$this->data = $dataString;
80+
return $this;
81+
}
82+
4783
/**
4884
* @param string $path
4985
*
5086
* @return bool|int
5187
*/
52-
public function convertAndSave($path): int
88+
public function convertAndSave(string $path): int
5389
{
5490
return file_put_contents($path, $this->convert());
5591
}
@@ -71,12 +107,12 @@ public function getFilename(): string
71107
}
72108

73109
/**
74-
* @param string $key
110+
* @param string $key
75111
* @param string|int $value
76112
*
77113
* @return array
78114
*/
79-
public function setConversionKey($key, $value): array
115+
public function setConversionKey(string $key, $value): array
80116
{
81117
$this->conversion[$key] = $value;
82118
return $this->conversion;

src/File/Csv.php

Lines changed: 55 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,31 +21,59 @@ class Csv extends AbstractFile
2121
];
2222

2323
/**
24-
* @return string
24+
* Converts CSV data to JSON.
25+
*
26+
* @return string JSON representation of CSV data.
2527
*/
2628
public function convert(): string
2729
{
2830
$data = $this->parseData();
2931
$keys = $this->parseCsv(array_shift($data));
30-
$splitKeys = array_map(function ($key) {
32+
$splitKeys = $this->splitKeys($keys);
33+
$jsonObjects = array_map([$this, 'convertLineToJson'], $data, array_fill(0, count($data), $splitKeys));
34+
$json = json_encode($jsonObjects, $this->conversion['options']);
35+
if (json_last_error() !== JSON_ERROR_NONE) {
36+
throw new \RuntimeException('JSON encoding failed: ' . json_last_error_msg());
37+
}
38+
return $json;
39+
}
40+
41+
/**
42+
* Splits keys based on the configured join delimiter.
43+
*
44+
* @param array $keys
45+
* @return array
46+
*/
47+
private function splitKeys(array $keys): array
48+
{
49+
return array_map(function ($key) {
3150
return explode($this->conversion['join'], $key);
3251
}, $keys);
33-
return json_encode(array_map(function ($line) use ($splitKeys) {
34-
return $this->getJsonObject($line, $splitKeys);
35-
}, $data), $this->conversion['options']);
3652
}
3753

3854
/**
39-
* @param $line
40-
* @param $splitKeys
41-
* @param array $jsonObject
55+
* Converts a CSV line to a JSON object.
4256
*
57+
* @param string $line
58+
* @param array $splitKeys
4359
* @return array
4460
*/
45-
private function getJsonObject($line, $splitKeys, array $jsonObject = []): array
61+
private function convertLineToJson(string $line, array $splitKeys): array
4662
{
47-
$values = $this->parseCsv($line);
48-
for ($valueIndex = 0, $count = \count($values); $valueIndex < $count; $valueIndex++) {
63+
return $this->getJsonObject($this->parseCsv($line), $splitKeys);
64+
}
65+
66+
/**
67+
* Creates a JSON object from a CSV line.
68+
*
69+
* @param array $values CSV values.
70+
* @param array $splitKeys Split keys.
71+
* @return array JSON object.
72+
*/
73+
private function getJsonObject(array $values, array $splitKeys): array
74+
{
75+
$jsonObject = [];
76+
for ($valueIndex = 0, $count = count($values); $valueIndex < $count; $valueIndex++) {
4977
if ($values[$valueIndex] === '') {
5078
continue;
5179
}
@@ -55,19 +83,21 @@ private function getJsonObject($line, $splitKeys, array $jsonObject = []): array
5583
}
5684

5785
/**
58-
* @param $splitKey
59-
* @param $splitKeyIndex
60-
* @param $jsonObject
61-
* @param $value
86+
* Sets a value in a JSON object.
87+
*
88+
* @param array $splitKey Split key.
89+
* @param int $splitKeyIndex Split key index.
90+
* @param array $jsonObject JSON object.
91+
* @param mixed $value Value.
6292
*/
63-
private function setJsonValue($splitKey, $splitKeyIndex, &$jsonObject, $value): void
93+
private function setJsonValue(array $splitKey, int $splitKeyIndex, array &$jsonObject, $value): void
6494
{
6595
$keyPart = $splitKey[$splitKeyIndex];
66-
if (\count($splitKey) > $splitKeyIndex + 1) {
96+
if (count($splitKey) > $splitKeyIndex + 1) {
6797
if (!array_key_exists($keyPart, $jsonObject)) {
6898
$jsonObject[$keyPart] = [];
6999
}
70-
$this->setJsonValue($splitKey, $splitKeyIndex+1, $jsonObject[$keyPart], $value);
100+
$this->setJsonValue($splitKey, $splitKeyIndex + 1, $jsonObject[$keyPart], $value);
71101
} else {
72102
if (is_numeric($value) && $this->conversion['numbers'] === 'numbers') {
73103
$value = 0 + $value;
@@ -77,11 +107,12 @@ private function setJsonValue($splitKey, $splitKeyIndex, &$jsonObject, $value):
77107
}
78108

79109
/**
80-
* @param $line
110+
* Parses a CSV line.
81111
*
82-
* @return array
112+
* @param string $line CSV line.
113+
* @return array Parsed CSV line.
83114
*/
84-
private function parseCsv($line): array
115+
private function parseCsv(string $line): array
85116
{
86117
return str_getcsv(
87118
$line,
@@ -92,7 +123,9 @@ private function parseCsv($line): array
92123
}
93124

94125
/**
95-
* @return array
126+
* Parses CSV data.
127+
*
128+
* @return array Parsed CSV data.
96129
*/
97130
private function parseData(): array
98131
{

0 commit comments

Comments
 (0)