Allow typecasting of values
tacman opened this issue · 5 comments
Feature Request
Q | A |
---|---|
New Feature | yes |
BC Break | no |
Proposal
When parsing CSV, the values are always strings:
$csvString = "name,age
bob,44";
$csvReader = Reader::createFromString($csvString)->setHeaderOffset(0);
var_dump($csvReader->first());
array(2) { ["name"]=> string(3) "bob" ["age"]=> string(2) "44" }
One idea is to typecast in the column itself, the other is to have an external schema.
$csvString = "name,age:int
bob,44";
$csvReader = Reader::createFromString($csvString)->setHeaderOffset(0);
$parser = new Parser($csvReader);
var_dump($parser->first());
array(2) { ["name"]=> string(3) "bob" ["age"]=> int 44 }
The idea for the CSV Parser comes from https://github.com/shakahl/csv-schema, but I modified it to allow embedding the types in the headers. It is part of a Symfony bundle I use when manipulating CSV files, which I'm now refactoring to use phpleague's excellent tools.
But it got me to thinking, perhaps there's a way to use even more of your tools, or incorporate this typecasting directly.
My test file for the parser looks like this right now. Maybe version 10 can incorporate some of these ideas.
tests:
- source: |
name,age
bob,22
expects: |
{"name":"bob","age":"22"}
- source: |
name,age
bob,22
map:
/age/: int
expects: |
{"name":"bob","age":22}
- source: |
name,age:int,married:bool
bob,22,1
expects: |
{"name":"bob","age":22, married: true}
- source: |
name,hobbies:array|
bob,"golf|poker"
expects: |
{"name":"bob","hobbies":["golf","poker"]}
@tacman thanks for the issue. There's a good reason why this type of casting is not handled by the library. What you are proposing is a step in object hydration or mapping. Ultimately you may want to convert your row or records into either a strongly type array or PHP objects and there are plenty of battle testing library in PHP world that do it better than league/csv will ever do. check this line from Valinor which list different pavckages that could be used to achieve your goal without having to change or add unnecessary feature to the package and its maintenance.
Thanks, I'll check that out!
@tacman since version 9.11.0
a Reader::addFormatter
method was added to allow you type the returned array
.
$reader = Reader::createFromString($csvString)->setHeaderOffset(0);
$reader->addFormatter(function (array $record): array {
$record['age'] = (int) $record['age'];
return $record;
});
var_dump($csvReader->first());
//returns array(2) { ["name"]=> string(3) "bob" ["age"]=> int 44 }
Ah, cool, I'll check it out! I've used the addFormatter on the writer, glad to see it on the reader as well!
@tacman FYI there's currently a PR in review to allow full typecasting on CSV records. feel free to comment or add remarks