How to send params in compose method of mailer yii2 - php

I'm trying to send one param ($id) to view layout\html.php using compose() method of mailer component. But i don't know how to get it
The code:
$id = 1;
Yii::$app->mailer->compose('\layouts\html.php', ['id' => $id])
->setFrom('stackfrom#gmail.com')
->setTo('stackto#gmail.com')
->setSubject('Email sent from Yii2-Swiftmailer')
->send();
And in a line of my view layout\html.php
<div><?php echo $id ?></div>
Error is here!

You don't call a view file with compose() method like this, you should use alias like #common, #frontend or any other relevant to the view you are trying to load mostly we place all views related to emails in common/mail so we will use #common alias in example.
You can use 2 ways
You may pass additional view parameters to compose() method, which will be available inside the view files.Yii::$app->mailer->compose('#common/path/to/view', ['id' => $id]);
Render HTML separately
$body =Yii::$app->view->renderFile('#common/path/to/view-file.php',['id'=>$id])
to render the HTML from the php file, pass it any parameters you want to like any normal view file and then attach it to the email body using setHtmlBody($body), use the following way
$body = Yii::$app->view->renderFile ( '#common/mail/account-activation.php' , [
'id' => $id
] );
Yii::$app->mailer->compose()
->setFrom('stackfrom#gmail.com')
->setTo('stackto#gmail.com')
->setSubject('Email sent from Yii2-Swiftmailer')
->setHtmlBody($body)
->send()
For more help see Documentation

Compose method takes special alias in format '#app/mail/layouts/default.php'
So if you are using absolute format, use # and path (yii2 aliases)
Reference to swift mailer you can see here: http://www.yiiframework.com/doc-2.0/yii-swiftmailer-mailer.html

Related

Edit email template in Laravel

I need to edit template which used for emails in admin panel. Any Ideas?
I think about several ways:
Save email template in DB in the text field, edit it in the admin panel and then display the text in the blade's view.
The problem of this way's realization is I have to display php variables in blade template and then use the final code as the html for email. I think, it's so difficult for Laravel.
And the additional problem is if I store {{ $var }} in template's text in DB - it will display as the text, blade compiler doesn't process it.
Store only the static text information from email in the DB and then display it in the template. PHP variables will transfer separately.
This way will solve the problem with the php var's display, but I still don't know how to use the final code in the Mail::send, because Laravel allows using the template's name only, not a HTML, as I know...
I think about the following way:
$view = view('template')->render();
mail(..., $view, ...);
But I don't want to use it because I want use Mail::queue() for querying emails and I don't know how to use it with PHP mail().
Thanks to everybody for replies.
You can create your own variable syntax and store email template as text in your DB. Foe example, you can store each variable as ${VARIABLE_KEY} string.
Then during email preparation you should resolve all such constructions into their real values. I don't know which variables are required, but during email preparation you should execute these steps:
Load email template from DB.
Replace all ${VARIABLE_KEY} with their real values.
You can use regular expressions for the searching and replacement, but also you can use functions such str_replace. For example, if you want to paste email of the current user into your email (and your table for model User has an email field), then you can create variable: ${user.name} and then replace this manually with simple str_replace function:
$variables['${user.name}'] = Auth::user()->email;
str_replace(array_keys($variables), array_values($variables), $yourEmailTemplateBody);
Also you can do replacements by the same method not only in the email template body, but in the email subject too.
Then you have to create your own class which extends Laravel Illuminate\Mail\Mailable class. In this class you should define build method, where you can use not only the name of the view, but also some additional parameters, like in the "regular" view, for example:
class SomeClassName extends Mailable
{
public function build()
{
$email = $this->view('mail.common', [
'mail_header' => 'some header',
'mail_footer' => 'some footer',
])->subject('Your subject');
...
return $email;
}
For example, in your view you can store layout for entire email with some extra parameters: footer and header as in my example.
Also you can create more complex syntax for ${VARIABLE_NAME} constructions, for example, VARIABLE_NAME can be a method definition in PHP or Laravel notation, i.e.: SomeClass::someStaticMethod. You can detect this case and resolve SomeClass via Laravel Service Container. Also it can be an object.field notation, for example, user.email, where user is the current Auth::user().
But be carefull in this cases: if you will grant ability to edit email templates with this variables for all users, you should filter fields or available methods and classes for calling to prevent executing any method of any available class in your email template or to prevent display private information.
You can read about writing mailables in Laravel documentation
I was doing this for a project yesterday and found a good post describing Alexander's answer in more detail. The core is creating an EmailTemplate model with this method:
public function parse($data)
{
$parsed = preg_replace_callback('/{{(.*?)}}/', function ($matches) use ($data) {
list($shortCode, $index) = $matches;
if( isset($data[$index]) ) {
return $data[$index];
} else {
throw new Exception("Shortcode {$shortCode} not found in template id {$this->id}", 1);
}
}, $this->content);
return $parsed;
}
Example usage:
$template = EmailTemplate::where('name', 'welcome-email')->first();
Mail::send([], [], function($message) use ($template, $user)
{
$data = [
'firstname' => $user->firstname
];
$message->to($user->email, $user->fullname)
->subject($template->subject)
->setBody($template->parse($data));
});
For all the details (db migration, unit test, etc), see the original post at http://tnt.studio/blog/email-templates-from-database
You can simply use this awesome laravel package:
https://github.com/Qoraiche/laravel-mail-editor
Features (from readme file):
Create mailables without using command line.
Preview/Edit all your mailables at a single place.
Templates (more than 20+ ready to use email templates).
WYSIWYG Email HTML/Markdown editor.

Laravel - edit data before passing to view

I'm looking for a way to edit data before passing them to view.
Quick example (just to demonstrate):
Let's say I am passing variable $name to a view through controller. I would like to use something to pass another variable $message which would contain Hello $name, so for example Hello John, if variable $name would be John.
I don't want to send this second variable in controller, because I'm gonna use a lot of controllers, views and the thing that I want to do with the data is rather complicated.
I need to use this for both variables view("foobar", ["foo" => "bar"]) and sessions view("foobar")->with("foo", "bar").
I've tried to use both Middleware and Service Provider but the problem was I couldn't access the sent data.
The only possible solution I can think of now is to use View layout which I'm going to include into every view and which is gonna transform the variables (using something like <? $message = "Hello $name"; ?> in the view), but this doesn't seem like the right MVC solution for me.
Thank you all for your answers!
If you want to pass session data and multiple variables, do this:
session()->flash('message', 'some message');
return view('foobar', [
'foo' => 'bar',
'second' => 'something'
]);
Update
If I understood you correctly, you want to use view composer.

Laravel 5.1 error when trying to pass variable to view

I have the following snippet of code, where I am trying to pass the email object to my view.
return response()->view('admin.editEmail')->with('email', $this->template->findTemplateById($id));
This results in the following error:
Call to undefined method Illuminate\Http\Response::with()
How can I fix this?
Just pass it as a second parameter in view():
return response()->view('admin.editEmail', $email);
Here are the docs for view->with(). You have to pass a key and a value for each variable you send. If you have multiple, you need to send an array of keys=>values. compact is useful for this.
$template = $this->template->findTemplateById($id)
response()->view('admin.editEmail')->with(compact('email', 'template'));
There are many different ways of doing this.
I prefer to use this one as you can easily add new variables.
In this way its also posible to have different variable names in your controller and view.
return view('admin.editEmail', [
'email' => $adminEmail,
'anotherVar' => $someValue,
]);
In this example the email in the controller is stored in $adminEmail but in the template we will receive it as $email.
With compact you need to have the same variable name in your controller as in your view.

How does CodeIgniter send information from a Model to a View with the Controller?

When I call a controller and it calls the model, model returns information from my database assigned to something in the controller.
But how does it "send" it to the view for rendering? How for example, when I send $data array to my_view.php. how does it get to that page so that, I am guessing, I can do things like use extract to get my individual variables.
I'm really asking at the php level, how would you send that data (so I can learn). How does that view know what I sent it?
Thanks.
You have to "send" that $data array to the view as the second parameter when you load it.
$data['user'] = array(
'name' => 'Tom Jones',
'gender' => 'male'
);
$this->load->view('blogview', $data);
Then, the contents of the array are accessed within the view by their corresponding key values
<?php echo $user['name']; ?>
Checkout out the docs for more details: http://codeigniter.com/user_guide/general/views.html
The general pattern of all php views is this:
function render_view($__filename, $__data) {
extract($__data);
include $__filename;
}
This is basically how CodeIgniter does it, but it uses a loader to find the view filename and includes output buffering options.

send email from model and template

if i want send email with SwiftMailer in symfony then i must in action:
$message = $this->getMailer()->compose(
array('user#gmail.com' => 'user'),
$affiliate->getEmail(),
'Jobeet affiliate token',
body
);
$this->getMailer()->send($message);
but this doesnt working in template and in model (i would like create function for this).
I wouldn't recommend sending mail using a template - put a link in the template and call the action to send the mail ... you can send from a model although again i wouldn't recommend it as using sfContext::getInstance() inside the model is a really bad practice as it makes the model class rely on the context. So, your model class can't be unit tested as it needs a context to work...
You need an instance of the current sfContext to do it ... i would suggest passing it as a parameter when you create the model

Categories