danog / MadelineProto

Async PHP client API for the telegram MTProto protocol
https://docs.madelineproto.xyz
GNU Affero General Public License v3.0
2.76k stars 619 forks source link

EventHandler serialization issue with dependency injection in SimpleEventHandler #1445

Closed a-kbv closed 7 months ago

a-kbv commented 7 months ago

Code Example

<?php

declare(strict_types=1);

namespace App\Service;

// ... (omitting namespace imports for brevity)

class BasicEventHandler extends SimpleEventHandler
{
    public const ADMIN = '@me';

    public function __construct(private \App\Repository\ProviderRepository $providerRepository) {}

    // ... (omitting other methods for brevity)

    #[Handler]
    public function handleMessage(Incoming&Message $message): void
    {
        $provider = $this->providerRepository->findOneBy(['id' => 1]);
        // ...
    }
}

BasicEventHandler::startAndLoop('bot.madeline');

Description

When using the BasicEventHandler class within my Symfony application, I have enabled dependency injection to provide a ProviderRepository. The injected repository is accessible and correctly instantiated within the constructor. However, a PHP error occurs when handleMessage is triggered by an incoming message, suggesting that the ProviderRepository has not been initialized. The error message is as follows:

Typed property App\Service\BasicEventHandler::$providerRepository must not be accessed before initialization

This issue seems to stem from the serialization behavior in the event-handling mechanism, which does not preserve the initialized state of dependencies.

Steps to Reproduce

  1. Set up a Symfony application with dependency injection.
  2. Define a BasicEventHandler service with a constructor that takes a ProviderRepository.
  3. Inject the ProviderRepository via Symfony's dependency injection.
  4. Start the BasicEventHandler loop using startAndLoop.
  5. Send a message to the bot that triggers the handleMessage method.
  6. Observe the PHP error indicating the uninitialized ProviderRepository.

Expected Behavior

The expected behavior is for the handleMessage method to access the injected and initialized ProviderRepository to process the incoming message.

Actual Behavior

An error is thrown indicating that the providerRepository property is being accessed before initialization, as though the property is not being serialized/deserialized along with the event handler's state.

Additional Context

Is there a recommended approach to handling dependency injection within an event handler that participates in serialization? Alternatively, should dependencies be fetched in a different manner when handling incoming messages in this context?


Note that you may need to adjust the code example, Symfony version, PHP version, and other specific details to match your actual environment.

danog commented 7 months ago

MadelineProto is not integrated with symfony, even if integration has been requested by a few people and will be implemented once I have some more time.

You can still easily use symfony's dependency injector by creating the ContainerBuilder and registering the yaml in onStart, or using another dependency injection library like php-di (still in onStart, not in the constructor).

a-kbv commented 7 months ago

Thank you for the response, but the suggested workaround doesn't completely resolve my issue. Unfortunately, I'm still unable to use blocking functions or classes like PDO within the event handler due to serialization concerns.

I understand MadelineProto offers an asynchronous processing environment, but I'm looking for a method to integrate blocking resources, such as those provided by Symfony's ORM. Simply replacing these with asynchronous alternatives isn't always feasible due to the extensive restructuring it would require within my existing codebase.

Can you provide guidance on how to use traditional, blocking PHP code within MadelineProto's event handlers? Can MadelineProto's event loop be paused or integrated with traditional blocking PHP code somehow?

If there are patterns or practices that you can suggest to bridge this gap, it would greatly benefit those of us trying to integrate MadelineProto with a Symfony-based application.