I have a PHP script that write into consol some logs,erros etc.
I want to save all this information into a variable for sending an email at the end of its execution.
I know i can use obstart and co for doing that but I also want that during its execution that the logs appear in real time. So I don't think the output buffering is the solution for my problem but I don't see another solution.
Is there a way for doing that please ?
Thanks by advance
You will have to come up with some kind of custom logger that apart from outputing messages to console will also send an email on script shutdown. Something like this:
interface MailerInterface {
function send($recipient, $title, $body);
}
interface LoggerInterface {
function log($message);
}
class ConsoleLoggerWithMailer implements LoggerInterface {
/**
* #var string[]
*/
private $messages = array();
/**
* #var MailerInterface
*/
private $mailer;
/**
* #var string
*/
private $recipient;
public function __construct() {
register_shutdown_function(array($this, 'sendMessages'));
}
/**
* #param MailerInterface $mailer
* #param string $recipient
*/
public function setMailer(MailerInterface $mailer, $recipient) {
$this->mailer = $mailer;
$this->recipient = $recipient;
}
/**
* #return string[]
*/
public function getMessages() {
return $this->messages;
}
public function log($message) {
$this->messages[] = $message;
printf("%s\n", $message);
}
public function sendMessages() {
if ($this->mailer === null || count($this->messages) === 0)
return;
$this->mailer->send($this->recipient, 'log', implode("\n", $this->messages));
}
}
Usage example assuming you also created some Mailer class implementing MailerInterface:
$mailer = new Mailer();
$logger = new ConsoleLoggerWithMailer();
$logger->setMailer($mailer, "webmaster#example.com");
$logger->log("Starting...");
$logger->log("Doing...");
$logger->log("End");
Related
I have been struggling to find way to replace From and Reply To addresses before email is sent out in the Mautic software.
I have created mautic_root/plugins/SenderRandBundle/EventListener/EmailSubscriber.php and its content:
<?php
namespace MauticPlugin\SenderRandBundle\EventListener;
use Doctrine\ORM\EntityManager;
use Mautic\CoreBundle\Helper\EmojiHelper;
use Mautic\CoreBundle\Helper\IpLookupHelper;
use Mautic\CoreBundle\Model\AuditLogModel;
// use Mautic\EmailBundle\EmailEvents;
// use Mautic\EmailBundle\Event as Events;
use Mautic\EmailBundle\Event\TransportWebhookEvent;
use Mautic\EmailBundle\Model\EmailModel;
// use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Translation\TranslatorInterface;
use Mautic\EmailBundle\EmailEvents;
use Mautic\EmailBundle\Event as Events;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Psr\Log\LoggerInterface;
use MauticPlugin\SenderRandBundle\Integration\Config;
/**
* Class EmailSubscriber
*/
class EmailSubscriber implements EventSubscriberInterface
{
/**
* #var AuditLogModel
*/
private $auditLogModel;
/**
* #var IpLookupHelper
*/
private $ipLookupHelper;
/**
* #var EmailModel
*/
private $emailModel;
/**
* #var TranslatorInterface
*/
private $translator;
/**
* #var EntityManager
*/
private $entityManager;
private $config;
public function __construct(
IpLookupHelper $ipLookupHelper,
AuditLogModel $auditLogModel,
EmailModel $emailModel,
TranslatorInterface $translator,
EntityManager $entityManager,
LoggerInterface $logger,
Config $config
) {
$this->ipLookupHelper = $ipLookupHelper;
$this->auditLogModel = $auditLogModel;
$this->emailModel = $emailModel;
$this->translator = $translator;
$this->entityManager = $entityManager;
$this->logger = $logger;
$this->config = $config;
}
/**
* #return array
*/
static public function getSubscribedEvents()
{
return array(
EmailEvents::EMAIL_ON_SEND => array('onEmailGenerate', 0),
);
}
/**
* Search and replace with content
*
* #param EmailSendEvent $event
*/
public function onEmailGenerate(Events\EmailSendEvent $event)
{
// Check if this plugin is enabled
if (!$this->config->isPublished()) {
return;
}
$email = $event->getEmail();
$fromAddress = $email->getFromAddress();
$replyToAddress = $email->getReplyToAddress();
if (!$email->getUseOwnerAsMailer()) {
// Check if email from address contains #sender.rand
if (strpos($fromAddress, '#sender.rand') !== false) {
// Get domains from plugin settings
$domains = explode(',', $this->config->getFeatureSettings()['integration']['domains']);
if (count($domains) > 0) {
// Choose random domain from domains
$domain = $domains[array_rand($domains)];
// Replace #sender.rand with chosen domain
$sender = str_replace('#sender.rand', '#' . $domain, $fromAddress);
// Update email from address
$email->setFromAddress($sender);
// Check if email reply to contains #sender.rand
if (strpos($replyToAddress, '#sender.rand') !== false) {
// Replace #sender.rand with chosen domain
$newReplyToAddress = str_replace('#sender.rand', '#' . $domain, $replyToAddress);
// Update email reply to address
$email->setReplyToAddress($newReplyToAddress);
}
}
}
}
}
}
Currently with this code, I am getting an email which From address is changed as intended, but Reply To address remains unchanged - this is problem I am trying to solve.
What's the best way to modify From and Reply To addresses before email is sent out?
Here is the piece of code. My idea is that each email comes out with one of the values/entry from one of my tables.
public function __construct($siniestro)
{
$this->siniestro = $siniestro;
$this->subject = {{ $siniestro->siniestro }};
}
[from this place I want to get my subject][1]
[1]: https://i.stack.imgur.com/D0PNO.png
this is all the code of my mailable
class ContactanosMailable extends Mailable
{
use Queueable, SerializesModels;
$this->subject = $siniestro->siniestro;
public $siniestro;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($siniestro)
{
$this->siniestro = $siniestro;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->view('emails.contactanos');
}
}
If I can add something else just let me know, and I will.
I hope this can reach, it's getting complicated
I would do it like that :
class ContactanosMailable extends Mailable
{
use Queueable, SerializesModels;
public $siniestro;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($siniestro)
{
$this->siniestro = $siniestro;
// set the subject property
$this->subject = $siniestro->siniestro;
// or use the subject method
$this->subject($siniestro->siniestro);
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->view('emails.contactanos');
}
}
using the subject() method looks cleaner but both works
public function build(){
$from_email = "test#mail.com";
$subject = "Account Request";
return $this->from($from_email)->subject($subject)->view('emails.contactanos')
;
}
Unfortunately, so far I am a complete beginner in creating a module in magento.
I need to send an email after adding the item to the cart.
As I understand it, I need to use the checkout_cart_product_add_after event
I created some files, but I don't understand how to send an email after adding the item to the cart
My/Module/etc/events.xml
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
<event name="checkout_cart_product_add_after">
<observer name="email_after_adding_product" instance="My\Module\Observer\SendEmailForCart"/>
</event>
My/Module/Observer/SendEmailForCart.php
<?php
namespace My\Module\Observer;
use Magento\Framework\Event\ObserverInterface;
use My\Module\Helper\Email;
class SendEmailForCart implements ObserverInterface
{
private $helperEmail;
public function __construct(
Email $helperEmail
) {
$this->helperEmail = $helperEmail;
}
public function execute(\Magento\Framework\Event\Observer $observer)
{
return $this->helperEmail->sendEmail();
}
}
My/Module/Helper/Email.php
<?php
namespace My\Module\Helper;
class Email extends \Magento\Framework\App\Helper\AbstractHelper
{
public function __construct(
)
{
}
public function sendEmail()
{
try {
} catch (\Exception $e) {
}
}
}
Please tell, what code I need to write in the Email.php file?
And do I need to create any additional files or modify the ones I showed above?
/**
* Recipient email config path
*/
const XML_PATH_EMAIL_RECIPIENT = 'contact/email/recipient_email';
/**
* #var \Magento\Framework\Mail\Template\TransportBuilder
*/
protected $_transportBuilder;
/**
* #var \Magento\Framework\Translate\Inline\StateInterface
*/
protected $inlineTranslation;
/**
* #var \Magento\Framework\App\Config\ScopeConfigInterface
*/
protected $scopeConfig;
/**
* #var \Magento\Store\Model\StoreManagerInterface
*/
protected $storeManager;
/**
* #var \Magento\Framework\Escaper
*/
protected $_escaper;
/**
* #param \Magento\Framework\App\Action\Context $context
* #param \Magento\Framework\Mail\Template\TransportBuilder $transportBuilder
* #param \Magento\Framework\Translate\Inline\StateInterface $inlineTranslation
* #param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
* #param \Magento\Store\Model\StoreManagerInterface $storeManager
*/
public function __construct(
\Magento\Framework\App\Action\Context $context,
\Magento\Framework\Mail\Template\TransportBuilder $transportBuilder,
\Magento\Framework\Translate\Inline\StateInterface $inlineTranslation,
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
\Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\Framework\Escaper $escaper
) {
parent::__construct($context);
$this->_transportBuilder = $transportBuilder;
$this->inlineTranslation = $inlineTranslation;
$this->scopeConfig = $scopeConfig;
$this->storeManager = $storeManager;
$this->_escaper = $escaper;
}
/**
* Post user question
*
* #return void
* #throws \Exception
*/
public function execute()
{
$post = $this->getRequest()->getPostValue();
if (!$post) {
$this->_redirect('*/*/');
return;
}
$this->inlineTranslation->suspend();
try {
$postObject = new \Magento\Framework\DataObject();
$postObject->setData($post);
$error = false;
$sender = [
'name' => $this->_escaper->escapeHtml($post['name']),
'email' => $this->_escaper->escapeHtml($post['email']),
];
$storeScope = \Magento\Store\Model\ScopeInterface::SCOPE_STORE;
$transport = $this->_transportBuilder
->setTemplateIdentifier('send_email_email_template') // this code we have mentioned in the email_templates.xml
->setTemplateOptions(
[
'area' => \Magento\Framework\App\Area::AREA_FRONTEND, // this is using frontend area to get the template file
'store' => \Magento\Store\Model\Store::DEFAULT_STORE_ID,
]
)
->setTemplateVars(['data' => $postObject])
->setFrom($sender)
->addTo($this->scopeConfig->getValue(self::XML_PATH_EMAIL_RECIPIENT, $storeScope))
->getTransport();
$transport->sendMessage();
$this->inlineTranslation->resume();
$this->messageManager->addSuccess(
__('Thanks for contacting us with your comments and questions. We\'ll respond to you very soon.')
);
$this->_redirect('*/*/');
return;
} catch (\Exception $e) {
$this->inlineTranslation->resume();
$this->messageManager->addError(__('We can\'t process your request right now. Sorry, that\'s all we know.'.$e->getMessage())
);
$this->_redirect('*/*/');
return;
}
}
Make a reasearch on your own in vendor/magento. There are many places where emails are sent. Look for $transport or $transportObject variable (don't remember)
I have created a mailable php artisan make:mail SendInEmail
class SendInEmail extends Mailable
{
use Queueable, SerializesModels;
public $email;
public $sub;
public $emailcontent;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($email, $sub, $emailcontent)
{
$this->email = $email;
$this->sub = $sub;
$this->emailcontent = $emailcontent;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->subject($sub)->view('emails.sendemail');
}
}
In the build function I am passing the $sub variable, which comes from the controller, but it gives me an error:
Undefined variable: sub
When I use this:
return $this->subject('Some subject')->view('emails.sendemail');
It works fine.
P.S I did some research and found that I need use function to pass the subject variable (some anonymous function magic) (Not sure how to do that with mailables)
You're using the wrong variable, so change it to $this->sub:
return $this->subject($this->sub)->view('emails.sendemail');
I am using Laravel 5.3 on homestead. Here's the code that I am using for broadcasting an event through pusher and laravel echo, to notify the users of a new message in real time -
class NewMessageReceived implements ShouldBroadcast
{
use InteractsWithSockets, SerializesModels;
public $message;
public $user;
public $sender;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct(Message $message, User $user)
{
$this->message = $message;
$this->user = $user;
$this->sender = \Auth::user();
}
/**
* Get the channels the event should broadcast on.
*
* #return Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('user.'. $this->user->id);
}
}
Here's the code that calls this event-
try{
$m = $privateChat->messages()->save($m);
if( isset(Auth::user()->guide))
event ( new NewMessageReceived( $m, $m->messageable->tourist->user ));
else
event ( new NewMessageReceived( $m, $m->messageable->guide->user ));
return $m;
}
catch(Exception $e){
return $e;
}
There's an ajax call in vue, which receives the response generated by above code i.e $m .
The problem is if I use the code below instead of the above code, response is recieved at least 5 times faster. I just need to remove the event-firing part to make it run faster (which is not desired, since I want to update user in real time)-
try{
$m = $privateChat->messages()->save($m);
return $m;
}
catch(Exception $e){
return $e;
}
It would be helpful if you could help me spot the reason behind this behaviour and how can I make it all happen in real time, instead of the delay existing now.
You should change ShouldBroadcast to ShouldBroadcastNow. That will solve the problem with delay.
Try this:
Move your if logic to event Class
class NewMessageReceived implements ShouldBroadcast
{
use InteractsWithSockets, SerializesModels;
public $message;
public $user;
public $sender;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct(Message $message)
{
$this->message = $message;
$this->user = isset(Auth::user()->guide)) ? $message->messageable->tourist->user : $this->user = $message->messageable->guide->user;
$this->sender = \Auth::user();
}
/**
* Get the channels the event should broadcast on.
*
* #return Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('user.'. $this->user->id);
}
}
Now your event call.
$m = $privateChat->messages()->save($m);
event(new NewMessageReceived($m));
return $m;