Giter VIP home page Giter VIP logo

Comments (12)

tacman avatar tacman commented on May 27, 2024 1

so in the example, it should be 'releaseYear', or something like that, then releaseYear would get mapped to releaseDate, which is a DateTime object.

from csv.

nyamsprod avatar nyamsprod commented on May 27, 2024 1

@tacman the feature is now complete and stable on the master branch you can already try it out... by downloading dev-master. The final documentation is also available already on the documentation website on https://csv.thephpleague.com/9.0/reader/record-mapping/

from csv.

tacman avatar tacman commented on May 27, 2024

I like the idea of mapping, and I have a few ideas.

i think the entity class itself should have a

#[League\Csv\Attribute\Sheet()]  // or Table() Csv()?
class Movie
{
    public string $title;
    public int $year;
    public string $imdbId;
}

If the property name matches (ignoring case matching snake-case, camelCase, spacing, etc.), then the mapping should happen automatically. That would cover the many common cases.

I like the cast: property, as that is often what is needed most. I'm wondering if we can have an inline function there,

#[Column(cast: fn(string $s) => (int)str_replace('tt', '', $s)] # changes tt1000 to 1000
public int $imdbId;

Ideally, we'd be able to handle related objects, but this requires more discussion.

class Subtitle {
     public Movie $movie;
     public string $isoLanguageCode;
}

One issue for me is a consistent way of defining an object with simple types (string, int, float, bool) without needing a DTO, but instead having some sort of configuration. That is, the results of these attributes act as same as adding a custom formatter.

$reader = Reader::createFromString($csvString)->setHeaderOffset(0);
$reader->addFormatter(function (array $record): array {
     foreach ($record as $var => $val) {
     $newValue = match($var) {
          'imdbId' => (int)str_replace('tt', '', $s),
          default($val)
    };
    $record[$var] = $val;
     return $record;
});

The missing step is mapping the $record to the DTO class. I usually use the Symfony serializer/normalizer services to do that.

Thanks for bringing this topic up, indeed it's complicated but I think will be very powerful.

from csv.

tacman avatar tacman commented on May 27, 2024

I have a Symfony bundle that uses this library, it's pretty messy because I used a different CsvReader before and now it's a mismash of code.

But brainstorming about what I'd like to see within that bundle, I can imaging firing a ReadRecord event that applied a formatter.

$reader = Reader::createFromString($csvString)->setHeaderOffset(0);
foreach ($reader as $row) {
    // events get called automatically, no need to specify here.
}

#[AsEventListener(event: CsvReaderEvent::READ_ROW, method: 'convert')]
class CsvReaderEventListener {
    public function convert(CsvReaderEvent $event): void
    {
        $record = $event->getRecord();
        $record['imdbId'] = str_replace('tt', '', $record['imdbId']);  
        $event->setRecord($record);
    }

I haven't thought through how the event would actually be structured, since multiple listeners could be called. At some point we need to call the map to move from the array to the object.

The reason to consider events is to inject services that can't be injected into the DTO.

Again, just brainstorming here.

from csv.

nyamsprod avatar nyamsprod commented on May 27, 2024

@tacman thanks for the feedback. First of all I do not plan on building yet another full blown serializer there are a lot of robust and battle test serializer out there (Symfony, Serde and in some way Valinor could be considered as great library to do so.)
The feature added in League\Csv allow some type of deserialization and will try to answer most of the use case but definetly not all of them.

IMHO...

#[League\Csv\Attribute\Sheet()]  // or Table() Csv()?
class Movie
{
    public string $title;
    public int $year;
    public string $imdbId;
}

is a great idea and will implement it. It resolve a lot of use case for the user. I think it will look like this in the end

#[Record]
class Movie
{
    public string $title;
    public int $year;
    public string $imdbId;
    #[Cell(offset:'imdbId' cast:CastToDate::class, castArguments:['format' => 'd-m-Y'])]
    public DateTimeInterface $releaseDate;
}

So that the Cell attribute can fine tune the casting if needed.

Adding closure or auto-resolving inner classes IMHO is out of context for now.

We might revisit it in the future but for now it would add a lot of burden on the feature. Right now the targetted audience is casting to simple DTO, everything with union or intersection type or auto-resolving unknown classes is IMHO out of scope.
Let's ship a simple feature which is easy to use and to extend and see how people react.

For now, if you really need a more complex casting I believe you are better of using a good old foreach loop on the Reader and apply you business logic sequencially... my 2 cents.

from csv.

tacman avatar tacman commented on May 27, 2024

Sounds good, I look forward to it.

Question: when you parse out the attributes, do you end up with a set of mapping rules? If so, it is possible to set those rules in some other way besides the class attributes? In my code, I created a schema map that went from the CSV column to the object property, by indeed it got ugly quickly!

Of course you'd want to leverage existing serializers. Perhaps documenting it would be enough for many users.

from csv.

tacman avatar tacman commented on May 27, 2024

what is the offset?

 #[Cell(offset:'imdbId'

?

from csv.

nyamsprod avatar nyamsprod commented on May 27, 2024

what is the offset?

 #[Cell(offset:'imdbId'

?

This is to specify the header offset or the record cell.

from csv.

nyamsprod avatar nyamsprod commented on May 27, 2024

so in the example, it should be 'releaseYear', or something like that, then releaseYear would get mapped to releaseDate, which is a DateTime object.

https://github.com/thephpleague/csv/blob/feature/object-casting/src/SerializerTest.php

you have concrete examples in the PR tests

from csv.

nyamsprod avatar nyamsprod commented on May 27, 2024

The feature is now available starting with version 9.12.0. Some changes and tweaks were done during testing period.

from csv.

thePanz avatar thePanz commented on May 27, 2024

Hi @nyamsprod , thanks for the implementation!

Would be nice to have the iterators for objects being typed
As an example (did not test the code)

    /**
     * @template T of object
     * 
     * @param class-string<T> $className
     * @param array<string> $header
     * @return iterator<T>
     *
     * @throws Exception
     * @throws MappingFailed
     * @throws TypeCastingFailed
     */
    public function getObjects(string $className, array $header = []): Iterator

from csv.

nyamsprod avatar nyamsprod commented on May 27, 2024

@thePanz you can submit a small PR with your addition I would gladly accept it after review 😉

from csv.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.