beyondcode / helo-laravel

HELO Laravel helper package to add
MIT License
87 stars 24 forks source link

[Octane] Error because of MailManager replacement #27

Closed maxeckel closed 4 months ago

maxeckel commented 3 years ago

Hey Folks,

I've just installed Octane (using Swoole) in a project where also Helo is used. The Workers constantly throw errors, telling that "setApplication()" does not exist on the Laravel7Mailer:

Method BeyondCode\HeloLaravel\Laravel7Mailer::setApplication does not exist.

at vendor/laravel/framework/src/Illuminate/Macroable/Traits/Macroable.php:103
     99▕      */
    100▕     public function __call($method, $parameters)
    101▕     {
    102▕         if (! static::hasMacro($method)) {
  ➜ 103▕             throw new BadMethodCallException(sprintf(
    104▕                 'Method %s::%s does not exist.', static::class, $method
    105▕             ));
    106▕         }
    107▕ 

I've chased this down to the call to Mail::swap($instance) in the HeloLaravelServiceProvider:26 . As by calling this method the underlying MailManager binding is swapped, this error appears.

If you are fine with e.g. adding a new Laravel8Mailer (which would add support for the setApplication method), as Octane requires Laravel 8, I'd be happy to PR this addition :) If you have another solution in mind (like adding the methods on the current mailer), I'd also be happy to take on the implementation ;)

Best regards,

Max

mpociot commented 3 years ago

Hi @maxeckel,

A Laravel8Mailer class would be a great solution for this. A PR would be great, thank you! :)

maxeckel commented 3 years ago

Hey @mpociot,

Thanks for the update!

I'll add a PR as soon as possible!

abishekrsrikaanth commented 3 years ago

@maxeckel any updates on a PR for this?

2h4services commented 2 years ago

I got this running, but I haven't tested it fully

src/HeloLaravelServiceProvider.php

     /**
     * Register the application services.
     */
    public function register()
    {
       ...
        $this->app->singleton(Mailer::class, function ($app) {
            if (version_compare($app->version(), '7.0.0', '<')) {
                return $this->createLaravel6Mailer($app);
            }

           //---[Changed]---
            if (version_compare($app->version(), '8.0.0', '<')) {
                return $this->createLaravel7Mailer($app);
            }

            return $this->createLaravel8Mailer($app);
        });
    }
    //Added method
    protected function createLaravel8Mailer($app)
    {
        $defaultDriver = $app['mail.manager']->getDefaultDriver();
        $config = $this->getConfig($defaultDriver);

        // Laravel 7 no longer bindes the swift.mailer:
        $swiftMailer = new Swift_Mailer($app['mail.manager']->createTransport($config));

        // Once we have create the mailer instance, we will set a container instance
        // on the mailer. This allows us to resolve mailer classes via containers
        // for maximum testability on said classes instead of passing Closures.
        $mailer = new Laravel8Mailer(
            'smtp', $app['view'], $swiftMailer, $app['events']
        );

        if ($app->bound('queue')) {
            $mailer->setQueue($app['queue']);
        }

        // Next we will set all of the global addresses on this mailer, which allows
        // for easy unification of all "from" addresses as well as easy debugging
        // of sent messages since they get be sent into a single email address.
        foreach (['from', 'reply_to', 'to', 'return_path'] as $type) {
            $this->setGlobalAddress($mailer, $config, $type);
        }

        return $mailer;
    }

New src/Laravel8Mailer.php

<?php

namespace BeyondCode\HeloLaravel;

use Illuminate\Contracts\Mail\Factory as MailFactory;
use Illuminate\Contracts\Mail\Mailer as MailerContract;

class Laravel8Mailer extends Mailer implements MailerContract, MailFactory
{
    public function mailer($name = null)
    {
        $this->currentMailer = $name;

        return $this;
    }

    /**
     * Set laravel application.
     *
     * @param \Illuminate\Contracts\Container\Container $app
     */
    public function setApplication($app)
    {
        $this->app = $app;
    }

    /**
     * Forget all of the resolved mailer instances.
     *
     * @return $this
     */
    public function forgetMailers()
    {
        $this->mailers = [];

        return $this;
    }
}