THELIA Forum

Welcome to the THELIA support and discusssion forum

Announcement

Rejoignez la communauté sur le Discord Thelia : https://discord.gg/YgwpYEE3y3

Offline

#1 Envoi de mail

(13-04-2017 09:03:31)


Bonjour,

Petite question: J'ai une petite commande dans mon Thélia qui vérifie les dates de validités des cartes enregistrés dans mon module d'abonnement, et j'aimerais envoyer un mail (render d'un template) pour alerter mon client que sa carte va expirer sous peu. Comment puis-je procéder SVP? Ou créer mon fichier template à rendre? Quelles méthodes utiliser dans ma classe CheckManager pour envoyer l'email?

Par avance merci pour votre aide

Offline

#2 Re: Envoi de mail

(13-04-2017 10:47:38)


Il te faut créer un message dans le B.O. - Configuration - Template e-mail. Tu peux pour ce faire utiliser un fichier template HTML, que tu placeras dans templates/email/default.

Ensuite dans ton contrôleur, tu vas utiliser une des méthodes du MailerFactory, par exemple sendEmailToCustomer() :

$this->getMailer()->sendEmailToCustomert(
   "code_de_ton_template_mail", 
   $customer, [
      "variable_mail_1" => "Valeur mail 1"
      ...
]);

$customer est une instance de Thelia\Model\Customer,, le 3eme paramètre permet de valuer les éventuelles variables présente dans ton mail.


OpenStudio Toulouse

Offline

#3 Re: Envoi de mail

(13-04-2017 12:34:57)


Merci pour ton retour rapide. Alors tout mon problème vient limite de la partie ou il faudrait récupérer/instancier un MailerFactory. En effet, mes checks ne sont pas faits dans un controller mais juste dans une  classe PaymentManager qui ressemble à ca:

namespace Subscription\Manager;


use Subscription\Model\PaiementMode;
use Subscription\Model\PaiementModeQuery;
use Thelia\Model\Customer;

class PaymentModeManager
{
    public static function alertPaymentModeToBeExpired()
    {
        $payments = PaiementModeQuery::create()->findOneByPmStatus(PaiementMode::STATUS_ACTIVE);

        /** @var PaiementMode $payment */
        foreach ($payments as $payment)
        {
            $today = new \DateTime('now');
            $validity = date_create_from_format('dmy', "01".$payment->getPmDateVal());

            $today->modify('last day of 1 month');
            $validity->modify("last day of this month");

            if ($today->format('Ymd') == $validity->format('Ymd'))
            {
                //Alert customer about expiration date of payment mode
                /** @var Customer $customer */
                $customer = $payment->getCustomer();
                //SEND EMAIL
            }
        }
    }
}

Comment pourrais-je procéder à ce niveau? D'après ma compréhension il me faudrait un EventDispatcherInterface et un ParserInterface pour instancier le MailerFactory mais je n'écoute aucun événement, je voudrais juste envoyer un mail si ma condition est remplie.

Merci

Offline

#4 Re: Envoi de mail

(13-04-2017 13:34:31)


Pas besoin d'écouter d’évènements, tu peux juste déclarer ta classe comme un service dans ton config.xml, et de lui passer les services dont tu as besoin.

Ensuite, au lie d’instancier la classe, tu la passera comme un servie de la classe qui l’utilise, etc.

Documente-toi sur la façon dont fonctionne l'injection de dépendances dans Symfony, c'est très pratique.


OpenStudio Toulouse

Offline

#5 Re: Envoi de mail

(13-04-2017 13:40:17)


J'ai déjà utilisé l'injection de dépendance sous Symfony mais je t'avoue que là je ne vois pas du tout comment je pourrais tourner ça.
Même si je passe ma classe PaymentManager en service, je ne vois pas ce que je pourrais lui passer comme service valide en paramètre pour obtenir un MailerFactory sans dispatcher

Offline

#6 Re: Envoi de mail

(13-04-2017 14:16:23)


        <service id="monmodule.monservice" class="Subscription\Manage\PaymentModeManagerr">
            <argument type="service" id="thelia.parser" />
            <argument type="service" id="mailer"/>
        </service>

Ensuite tu récupères ton service "monmodule.monservice" là ou tu as besoin de l'utiliser.

Alternative (que personnellement je préfère) : faire de ce service un listener, avec un event spécifique, et déclencher ton envoi de mail suite à réception de l'event.


OpenStudio Toulouse

Offline

#7 Re: Envoi de mail

(13-04-2017 15:40:16)


Génial, merci

Offline

#8 Re: Envoi de mail

(14-04-2017 15:50:36)


Flûte, je suis coincé. J'ai fait ma commande:

class CheckPaymentCardsExpirationDate extends ContainerAwareCommand
{

    protected function configure()
    {
        $this
            ->setName("subscription:checkPaymentCard")
            ->setDescription("Checks payment cards validity (expiration date)");
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $output->writeln("Starting");
        $output->writeln("Processing payment cards");
        PaymentModeManager::alertPaymentModeToBeExpired($this->getDispatcher());
        $output->writeln("Done !");
    }
}

Mon manager:

class PaymentModeManager
{
    public static function alertPaymentModeToBeExpired(EventDispatcher $dispatcher)
    {
        $payments = PaiementModeQuery::create()->findByArray([
            'pmStatus' => PaiementMode::STATUS_ACTIVE,
            'pmRegMode' => PaiementMode::REG_MODE_CB
        ]);

        /** @var PaiementMode $payment */
        foreach ($payments as $payment)
        {
            $today = new \DateTime('now');
            $validity = date_create_from_format('dmy', "01".$payment->getPmDateVal());

            $today->modify('last day of 1 month');
            $validity->modify("last day of this month");

            if ($today->format('Ymd') == $validity->format('Ymd'))
            {
                //Alert customer about expiration date of payment mode
                $alertEvent = new PaymentModeEvent($payment);
                $dispatcher->dispatch(PaymentModeEvent::PAYMENT_MODE_TO_BE_EXPIRED,
                    $alertEvent);
            }
        }
    }
}

Dans mon Config.xml

<services>
        <service id="subscription.payment.expire.listener" class="Subscription\EventListeners\SendMail">
            <argument type="service" id="mailer"/>
            <tag name="kernel.event_subscriber"/>
        </service>
    </services>

Mon listener sendMail

class SendMail implements EventSubscriberInterface
{
    /** @var MailerFactory */
    protected $mailer;

    public function __construct(MailerFactory $mailer)
    {
        $this->mailer = $mailer;
    }

    /**
     * Send email to notify customer that files for virtual products are available
     *
     * @param OrderEvent $event
     * @throws \Exception
     */
    public function sendEmail(PaymentModeEvent $event)
    {

        $paymentMode = $event->getPaymentMode();
        /** @var Customer $customer */
        $customer = $paymentMode->getCustomer();

        if (Subscription::getConfigValue(Subscription::ALERT_PAYMENT_MODE_EXPIRES_MESSAGE)) {
            $this->mailer->sendEmailToCustomer(
                Subscription::ALERT_PAYMENT_MODE_EXPIRES_MESSAGE,
                $customer,
                [
                    'firstName'  => $customer->getFirstname(),
                    'card_alias' => $paymentMode->getPmAlias()
                ]
            );
        }
    }


    /**
     * Returns an array of event names this subscriber wants to listen to.
     *
     * The array keys are event names and the value can be:
     *
     *  * The method name to call (priority defaults to 0)
     *  * An array composed of the method name to call and the priority
     *  * An array of arrays composed of the method names to call and respective
     *    priorities, or 0 if unset
     *
     * For instance:
     *
     *  * array('eventName' => 'methodName')
     *  * array('eventName' => array('methodName', $priority))
     *  * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
     *
     * @return array The event names to listen to
     *
     * @api
     */
    public static function getSubscribedEvents()
    {
        return array(
            PaymentModeEvent::PAYMENT_MODE_TO_BE_EXPIRED => array("sendEmail", 128)
        );
    }
}

et quand j'execute:

Starting
Processing payment cards
PHP Fatal error:  Uncaught Symfony\Component\Debug\Exception\FatalThrowableError: Fatal error: Call to a member function getSession() on null in /var/www/eshop/core/lib/Thelia/Core/Template/ParserContext.php:289
Stack trace:
#0 /var/www/eshop/core/lib/Thelia/Core/Template/ParserContext.php(233): Thelia\Core\Template\ParserContext->getSession()
#1 /var/www/eshop/core/lib/Thelia/Core/Template/ParserContext.php(59): Thelia\Core\Template\ParserContext->cleanOutdatedFormErrorInformation()
#2 /var/www/eshop/cache/dev/CoreDevDebugProjectContainer.php(4663): Thelia\Core\Template\ParserContext->__construct(Object(Symfony\Component\HttpFoundation\RequestStack), Object(Thelia\Core\Form\TheliaFormFactory), Object(Thelia\Core\Form\TheliaFormValidator))
#3 /var/www/eshop/core/vendor/symfony/dependency-injection/Container.php(312): CoreDevDebugProjectContainer->getThelia_Parser_ContextService()
#4 /var/www/eshop/cache/dev/CoreDevDebugProjectContainer.php(4590): Symfony\Component\DependencyInjection\Container->get('thelia.parser.c...')
#5 /va in /var/www/eshop/core/lib/Thelia/Core/Template/ParserContext.php on line 289

Qu'ai-je loupé please?

Offline

#9 Re: Envoi de mail

(14-04-2017 16:42:09)


Dans une commande, l'objet request est absent ! Il faut en fabriquer un et l'injecter dans le container.

Ajoute ça dans ta commande :

    protected function init()
    {
        $container = $this->getContainer();

        $request = new Request();
        $request->setSession(new Session(new MockArraySessionStorage()));

        /** @var RequestStack $requestStack */
        $requestStack = $container->get('request_stack');
        $requestStack->push($request);
    }

OpenStudio Toulouse

Offline

#10 Re: Envoi de mail

(14-04-2017 16:52:04)


Super, je l'avais trouvé sur une autre de tes réponses, mais au niveau des types j'avais pris Symfony\Component\HttpFoundation\Session\Session plutot que Thelia\Core\HttpFoundation\Session\Session et ça plantait.

J'ai corrigé la et ça fonctionne.
Merci

Offline

#11 Re: Envoi de mail

(25-06-2018 16:46:19)


Bonjour,

je me permets de déterrer ce post puisque je cherche également à envoyer un email depuis une ligne de commande. Ca coince lors du MailerFactory.

J'ai une Class Notification qui extends ContainerAwareCommand sur laquelle j'ai rajouté la fonction init() de Roadster.

Une Class DocumentManager qui dispatche vers les events JokerKit::DOCUMENT_EXPIRED ou JokerKit::DOCUMENT_TO_BE_EXPIRED
Visiblement, il faut utiliser un dispatcher spécifique lorsqu'on travaille depuis la ligne de commande (ContainerAwareEventDispatcher)

use Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher;

class DocumentManager
{
    public static function alertDocumentsToBeExpired(ContainerAwareEventDispatcher $dispatcher)
    {
        
            $dispatcher->dispatch(JokerKit::DOCUMENT_EXPIRED, $alertEvent);

            OU

            $dispatcher->dispatch(JokerKit::DOCUMENT_TO_BE_EXPIRED, $alertEvent);
    }
}

Enfin, mon écouteur d'évènements dont le constructeur qui ne fonctionne pas :

namespace JokerKit\EventListeners;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use JokerKit\JokerKit;


class SendAdminEmail implements EventSubscriberInterface
{
    /** @var MailerFactory */
    protected $mailer;

    public function __construct(MailerFactory $mailer)
    {
        $this->mailer = $mailer;
    }

    public static function getSubscribedEvents()
    {
        return array(
            JokerKit::DOCUMENT_TO_BE_EXPIRED => array("sendWarningAdminEmail", 128),
            JokerKit::DOCUMENT_EXPIRED => array("sendErrorAdminEmail", 128)
        );
    }

    /**
     * Send email to notify administrators that documents will expires soon.
     *
     * @param DocumentEvent $event
     * @throws \Exception
     */
    public function sendWarningAdminEmail(DocumentEvent $event)
    {
        $documentTitle = $event->getTitle();
        // Send warning email
    }

    /**
     * Send email to notify administrators that documents have been expired.
     *
     * @param DocumentEvent $event
     * @throws \Exception
     */
    public function sendErrorAdminEmail(DocumentEvent $event)
    {
        $documentTitle = $event->getTitle();
        // Send error email
    }
}
?>

Dans le fichier config du module, j'ai bien renseigné le service Mailer pour mon écouteur :
<services>
        <service id="jokerkit.document.expire.listener" class="JokerKit\EventListeners\SendAdminEmail">
            <argument type="service" id="mailer"/>
            <tag name="kernel.event_subscriber"/>
        </service>
</services>

J'obtiens cette erreur :
PHP Fatal error:  Uncaught Symfony\Component\Debug\Exception\FatalThrowableError: Type error: Argument 1 passed to JokerKit\EventListeners\SendAdminEmail::__construct() must be an instance of JokerKit\EventListeners\MailerFactory, instance of Thelia\Mailer\MailerFactory given, called in /var/www/vhosts/demo.joker-courses.com/httpdocs/cache/dev/CoreDevDebugProjectContainer.php on line 966 in /var/www/vhosts/demo.joker-courses.com/httpdocs/local/modules/JokerKit/EventListeners/SendAdminEmail.php:14

Stack trace:
#0 /var/www/vhosts/demo.joker-courses.com/httpdocs/cache/dev/CoreDevDebugProjectContainer.php(966): JokerKit\EventListeners\SendAdminEmail->__construct(Object(Thelia\Mailer\MailerFactory))

#1 /var/www/vhosts/demo.joker-courses.com/httpdocs/core/vendor/symfony/dependency-injection/Container.php(312): CoreDevDebugProjectContainer->getJokerkit_Document_Expire_ListenerService()

#2 /var/www/vhosts/demo.joker-courses.com/httpdocs/core/vendor/symfony/event-dispatcher/ContainerAwareEventDispatcher.php(183): Symfony\Component\Depe in /var/www/vhosts/demo.joker-courses.com/httpdocs/local/modules/JokerKit/EventListeners/SendAdminEmail.php on line 14

Une aide serait fort généreuse.

Offline

#12 Re: Envoi de mail

(25-06-2018 17:54:40)


Il te manque un use pour la classe MailerFactory, et un autre pour DocumentEvent.

Un IDE un peu évolué genre PhpStorm te permettrais de voir ces problèmes en un clin d’œil.


OpenStudio Toulouse

Offline

#13 Re: Envoi de mail

(26-06-2018 09:25:39)


J'ai encore un peu de mal à appréhender les services et les évènements, alors je me perds vite. Là c'est bête comme erreur désolé du dérangement et merci !

Offline

#14 Re: Envoi de mail

(26-06-2018 12:09:12)


Pas de soucis :-)


OpenStudio Toulouse