jolicode / elastically

🔍 JoliCode's Elastica wrapper to bootstrap Elasticsearch PHP integrations
248 stars 36 forks source link

Document->setData() is not supposed to accept DTO. #148

Closed VincentLanglet closed 1 year ago

VincentLanglet commented 1 year ago

Hi @damienalexandre, @lyrixx

In the doc, there is the following example

$dto = new Beer();
$dto->bar = 'American Pale Ale';
$dto->foo = 'Hops from Alsace, France';

// Add a document to the queue
$indexer->scheduleIndex('beers', new Document('123', $dto));
$indexer->flush();

but this is throwing static analysis issues because the second parameter $data is supposed to be a string|array https://github.com/ruflin/Elastica/blob/8.x/src/Document.php#L43

This also means that one day, when typehint will be added to elastica, the solution with DTO won't work anymore.

I was surprised it currently works, but discovered it was because of the following code https://github.com/jolicode/elastically/blob/master/src/Indexer.php#L45-L48, but this won't work the day native typehint will be added to setData/getData methods.

I'm not familiar with the library and the strategy behind but a proper way to change this could be:

Another way could be to change the scheduleIndex signature from

scheduleIndex($index, Document $document)

to

public function scheduleIndex(string|Index $index, ?string $id, string|data|object $data))
    {
        if (\is_object($data)) {
            $context = $this->contextBuilder->buildContext(\get_class($data));
            $data = $this->serializer->serialize($data, 'json', $context);
        }

        $document = new Document($id, $data, $index);
        $this->getCurrentBulk()->addDocument($document, Bulk\Action::OP_TYPE_INDEX);

        $this->flushIfNeeded();
    }

WDYT ? Do you see another way solution to

jdreesen commented 1 year ago

See also #70 and #105

lyrixx commented 1 year ago

Hello

Thanks for your issue.

We have already discussed that in this issue https://github.com/jolicode/elastically/issues/70 and we decided to do nothing

VincentLanglet commented 1 year ago

We have already discussed that in this issue #70 and we decided to do nothing

Sorry, I missed the issue when creating mine. However, I'm a little bit sad with this answer.

I agree that I don't have a good feeling with the solution proposed in https://github.com/jolicode/elastically/pull/105 which doesn't feel natural. In this PR, you said

Maybe we can sent an PR upstream to fix the typehint

That was my first thought, so I fork the elastica project and look at the code and how it's used. The document data won't work if I pass an object and don't use elastically. So the fact we can use a DTO is specifically a feature added by elastically. Therefore the elastica phpdoc is correct, they only supports array and string.

IMHO this does not make any sense. We must not modify code for the sake of a tool. For now the code works as expected and because some PHP doc are wrong, some tools return false positives. I think we are going in the wrong direction

I can dedicate time to work on this and solve the issue. I would really appreciate if you consider and accept one solution.

Maybe you would be ok with the first solution (exposing a prepareData method in the indexer or in another service) ? This way:

lyrixx commented 1 year ago

Thanks for time! this is really cool to see people wanting to fix issues.

I agree with you, it would be better so solve this issue once for all.

I did not try, but could it work with a custom Elastically\Document class? Of course, this class will extends the Elastica one. But it'll add another method, like getDto()?

edit: let's try: https://github.com/jolicode/elastically/pull/149

VincentLanglet commented 1 year ago

I did not try, but could it work with a custom Elastically\Document class? Of course, this class will extends the Elastica one. But it'll add another method, like getDto()?

edit: let's try: #149

This is an awesome idea indeed !

VincentLanglet commented 1 year ago

Solved by https://github.com/jolicode/elastically/pull/150