Skip to content

Commit

Permalink
added fromString method, improved code
Browse files Browse the repository at this point in the history
  • Loading branch information
ozdemirburak committed Oct 21, 2023
1 parent a24e069 commit eae0c86
Show file tree
Hide file tree
Showing 13 changed files with 234 additions and 88 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
language: php

php:
- 7.3
- 7.4
- 8.0
- 8.1
- 8.2

sudo: false

Expand Down
2 changes: 1 addition & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# The MIT License (MIT)

Copyright (c) 2020 Burak Özdemir
Copyright (c) 2023 Burak Özdemir

> Permission is hereby granted, free of charge, to any person obtaining a copy
> of this software and associated documentation files (the "Software"), to deal
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ $json->convertAndSave(__DIR__ . '/above.csv');
$json->convertAndDownload();
```

You can also convert directly from a JSON string using the `fromString` method.

``` php
$csvString = (new Json())->fromString('{"name": "Buddha", "age": 80}')->convert();
```

Assume that the input JSON is something like below.

```json
Expand Down Expand Up @@ -82,6 +88,12 @@ $csv->convertAndSave(__DIR__ . '/below.json');
$csv->convertAndDownload();
```

You can also convert directly from a CSV string using the `fromString` method.

``` php
$jsonString = (new Csv())->fromString('[{"name":"Buddha","age":"80"}]')->convert();
```

Assume that the input CSV file is something like below.

**SepalLength**|**SepalWidth**|**PetalLength**|**PetalWidth**|**Name**
Expand Down
60 changes: 48 additions & 12 deletions src/AbstractFile.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,49 +7,85 @@ abstract class AbstractFile
/**
* @var array
*/
protected $conversion;
protected $conversion = [];

/**
* @var string
*/
protected $data;
protected $data = '';

/**
* @var string
*/
protected $filename;
protected $filename = '';

/**
* CsvToJson constructor.
* AbstractFile constructor.
*
* @param string|null $filepath
*/
public function __construct(?string $filepath = null)
{
if ($filepath !== null) {
$this->loadFile($filepath);
}
}

/**
* Load data from a file.
*
* @param string $filepath
*/
public function __construct($filepath)
protected function loadFile(string $filepath): void
{
if (!is_readable($filepath)) {
throw new \RuntimeException("File not readable: $filepath");
}
[$this->filename, $this->data] = [pathinfo($filepath, PATHINFO_FILENAME), file_get_contents($filepath)];
}

/**
* @param null $filename
* @param string|null $filename
* @param bool $exit
*/
public function convertAndDownload($filename = null, $exit = true)
public function convertAndDownload(?string $filename = null, bool $exit = true): void
{
$filename = $filename ?? $this->filename;
header('Content-disposition: attachment; filename=' . $filename . '.' . $this->conversion['extension']);
header('Content-type: ' . $this->conversion['type']);
$this->sendHeaders($filename);
echo $this->convert();
if ($exit === true) {
exit();
}
}

/**
* Send headers for download.
*
* @param string $filename
*/
protected function sendHeaders(string $filename): void
{
header('Content-disposition: attachment; filename=' . $filename . '.' . $this->conversion['extension']);
header('Content-type: ' . $this->conversion['type']);
}

/**
* @param string $dataString
*
* @return $this
*/
public function fromString(string $dataString): AbstractFile
{
$this->data = $dataString;
return $this;
}

/**
* @param string $path
*
* @return bool|int
*/
public function convertAndSave($path): int
public function convertAndSave(string $path): int
{
return file_put_contents($path, $this->convert());
}
Expand All @@ -71,12 +107,12 @@ public function getFilename(): string
}

/**
* @param string $key
* @param string $key
* @param string|int $value
*
* @return array
*/
public function setConversionKey($key, $value): array
public function setConversionKey(string $key, $value): array
{
$this->conversion[$key] = $value;
return $this->conversion;
Expand Down
77 changes: 55 additions & 22 deletions src/File/Csv.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,31 +21,59 @@ class Csv extends AbstractFile
];

/**
* @return string
* Converts CSV data to JSON.
*
* @return string JSON representation of CSV data.
*/
public function convert(): string
{
$data = $this->parseData();
$keys = $this->parseCsv(array_shift($data));
$splitKeys = array_map(function ($key) {
$splitKeys = $this->splitKeys($keys);
$jsonObjects = array_map([$this, 'convertLineToJson'], $data, array_fill(0, count($data), $splitKeys));
$json = json_encode($jsonObjects, $this->conversion['options']);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new \RuntimeException('JSON encoding failed: ' . json_last_error_msg());
}
return $json;
}

/**
* Splits keys based on the configured join delimiter.
*
* @param array $keys
* @return array
*/
private function splitKeys(array $keys): array
{
return array_map(function ($key) {
return explode($this->conversion['join'], $key);
}, $keys);
return json_encode(array_map(function ($line) use ($splitKeys) {
return $this->getJsonObject($line, $splitKeys);
}, $data), $this->conversion['options']);
}

/**
* @param $line
* @param $splitKeys
* @param array $jsonObject
* Converts a CSV line to a JSON object.
*
* @param string $line
* @param array $splitKeys
* @return array
*/
private function getJsonObject($line, $splitKeys, array $jsonObject = []): array
private function convertLineToJson(string $line, array $splitKeys): array
{
$values = $this->parseCsv($line);
for ($valueIndex = 0, $count = \count($values); $valueIndex < $count; $valueIndex++) {
return $this->getJsonObject($this->parseCsv($line), $splitKeys);
}

/**
* Creates a JSON object from a CSV line.
*
* @param array $values CSV values.
* @param array $splitKeys Split keys.
* @return array JSON object.
*/
private function getJsonObject(array $values, array $splitKeys): array
{
$jsonObject = [];
for ($valueIndex = 0, $count = count($values); $valueIndex < $count; $valueIndex++) {
if ($values[$valueIndex] === '') {
continue;
}
Expand All @@ -55,19 +83,21 @@ private function getJsonObject($line, $splitKeys, array $jsonObject = []): array
}

/**
* @param $splitKey
* @param $splitKeyIndex
* @param $jsonObject
* @param $value
* Sets a value in a JSON object.
*
* @param array $splitKey Split key.
* @param int $splitKeyIndex Split key index.
* @param array $jsonObject JSON object.
* @param mixed $value Value.
*/
private function setJsonValue($splitKey, $splitKeyIndex, &$jsonObject, $value): void
private function setJsonValue(array $splitKey, int $splitKeyIndex, array &$jsonObject, $value): void
{
$keyPart = $splitKey[$splitKeyIndex];
if (\count($splitKey) > $splitKeyIndex + 1) {
if (count($splitKey) > $splitKeyIndex + 1) {
if (!array_key_exists($keyPart, $jsonObject)) {
$jsonObject[$keyPart] = [];
}
$this->setJsonValue($splitKey, $splitKeyIndex+1, $jsonObject[$keyPart], $value);
$this->setJsonValue($splitKey, $splitKeyIndex + 1, $jsonObject[$keyPart], $value);
} else {
if (is_numeric($value) && $this->conversion['numbers'] === 'numbers') {
$value = 0 + $value;
Expand All @@ -77,11 +107,12 @@ private function setJsonValue($splitKey, $splitKeyIndex, &$jsonObject, $value):
}

/**
* @param $line
* Parses a CSV line.
*
* @return array
* @param string $line CSV line.
* @return array Parsed CSV line.
*/
private function parseCsv($line): array
private function parseCsv(string $line): array
{
return str_getcsv(
$line,
Expand All @@ -92,7 +123,9 @@ private function parseCsv($line): array
}

/**
* @return array
* Parses CSV data.
*
* @return array Parsed CSV data.
*/
private function parseData(): array
{
Expand Down
Loading

0 comments on commit eae0c86

Please sign in to comment.