Update swiftmailer configuration based on user input - yii2

I need to update SwiftMailer configuration based on user input, particularly, the user may decide to send emails using SMTP protocol or store them locally (in an specific filesystem's folder). The user will use a view to decide the option, then the controller catch the decision and update a session var. The current approach is to read that session var from config/web.php and then choose the appropriate configuration.
I am not sure whether web.php is loaded just once during the application execution, in fact I can not check if the session is active and then get the info from the var. I'm not sure what approach may be the appropriate one.
This is my config/web.php:
<?php
use yii\web\Session;
$params = require __DIR__ . '/params.php';
$db = require __DIR__ . '/db.php';
$session = Yii::$app->session;
if($session->isActive){
$mailTransport = Yii::app()->session->get('emailtransport');
}
else{ //session is not started
$mailTransport = 'local';
}
if($mailTransport=='local'){
$config = [
'id' => 'basic',
'basePath' => dirname(__DIR__),
'bootstrap' => ['log'],
'aliases' => [
'#bower' => '#vendor/bower-asset',
'#npm' => '#vendor/npm-asset',
],
'components' => [
'request' => [
// !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
'cookieValidationKey' => 'a4ARdWYauHJ-UEAvVfagzk0LTyT_KEuZ',
],
'cache' => [
'class' => 'yii\caching\FileCache',
],
'user' => [
'identityClass' => 'app\models\User',
'enableAutoLogin' => true,
],
'errorHandler' => [
'errorAction' => 'site/error',
],
'mailer' => [
'class' => 'yii\swiftmailer\Mailer',
'viewPath' => '#app/mail',
'htmlLayout' => 'layouts/main-html', //template to Send Emails Html based
'textLayout' => 'layouts/main-text', //template to Send Emails text based
'messageConfig' => [
'charset' => 'UTF-8',
'from' => ['clients#ok.com' => 'OK Premiun Clients'],
], //end of messageConfig
// send all mails to a file by default. You have to set
// 'useFileTransport' to false and configure a transport
// for the mailer to send real emails.
'useFileTransport' => true,
//'useFileTransport' => false,
'transport' => [
'class' => 'Swift_SmtpTransport',
'host' => 'smtp.gmail.com',
'username' => 'ok#gmail.com',
'password' => "password",
'port' => '465',
'encryption' => 'ssl',
],
],
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
'class' => 'yii\log\FileTarget',
'levels' => ['error', 'warning'],
],
],
],
'db' => $db,
/*
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
],
],
*/
],
'params' => $params,
];
}//end of if loop
else{
$config = [
'id' => 'basic',
'basePath' => dirname(__DIR__),
'bootstrap' => ['log'],
'aliases' => [
'#bower' => '#vendor/bower-asset',
'#npm' => '#vendor/npm-asset',
],
'components' => [
'request' => [
// !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
'cookieValidationKey' => 'a4ARdWYauHJ-UEAvVfagzk0LTyT_KEuZ',
],
'cache' => [
'class' => 'yii\caching\FileCache',
],
'user' => [
'identityClass' => 'app\models\User',
'enableAutoLogin' => true,
],
'errorHandler' => [
'errorAction' => 'site/error',
],
'mailer' => [
'class' => 'yii\swiftmailer\Mailer',
'viewPath' => '#app/mail',
'htmlLayout' => 'layouts/main-html', //template to Send Emails Html based
'textLayout' => 'layouts/main-text', //template to Send Emails text based
'messageConfig' => [
'charset' => 'UTF-8',
'from' => ['ok#namesilo.com' => 'OK Premiun Clients'],
], //end of messageConfig
// send all mails to a file by default. You have to set
// 'useFileTransport' to false and configure a transport
// for the mailer to send real emails.
'useFileTransport' => false,
'transport' => [
'class' => 'Swift_SmtpTransport',
'host' => 'smtp.gmail.com',
'username' => 'ok#gmail.com',
'password' => "password",
'port' => '465',
'encryption' => 'ssl',
],
],
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
'class' => 'yii\log\FileTarget',
'levels' => ['error', 'warning'],
],
],
],
'db' => $db,
/*
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
],
],
*/
],
'params' => $params,
];
}//end of if else loop
Because the session is never reached on web.php the emails are always stored locally.

What you are trying to do requires you to instantiate the yii\swiftmailer\Mailer class from within your code and set the transport by calling setTransport(), rather than using it via defining under the components in the config file.
I will give you an example where i will use the smtp.gmail.com as the host for the transport and send an email
public function actionTest(){
//instantiate the mailer
$mailer = new \yii\swiftmailer\Mailer(
[
'useFileTransport' => false
]
);
//set the transport params
$mailer->setTransport(
[
'class' => 'Swift_SmtpTransport',
'host' => 'smtp.gmail.com',
'username' => 'username',
'password' => 'password',
'port' => '587',
'encryption' => 'tls'
]
);
//to email
$to = "someemail#gmail.com";
//email subject
$subject = "this is a test mail";
//email body
$body ="Some body text for email";
//send the email
$mailer->compose()->setTo($to)->setFrom(
[
'support#site.com' => 'Site Support'
]
)->setTextBody($body)->setSubject($subject)->send();
}

Another solution is this: I did some changes using my Model Class:
public function sendMail($transport, $view, $subject, $params = []){
//set layout params
\Yii::$app->mailer->getView()->params['userName'] = $this->username;
if($transport == 'local'){
\Yii::$app->mailer->useFileTransport=true;
}
else{
\Yii::$app->mailer->useFileTransport=false;
}
$result = \Yii::$app->mailer->compose([
'html' => 'views/' . $view . '-html',
'text' => 'views/' . $view . '-text',
], $params)->setTo([$this->email => $this->username])
->setSubject($subject)
->send();
//reset layout params
\Yii::$app->mailer->getView()->params['userName'] = null;
return $result;
} //end of sendMail
It helped me to simplify my web.php, it wasn't necessary to use session vars.

Related

PendalF89/yii2-filemanager upload error. (Call to a member function saveAs() on null)

getting
Call to a member function saveAs() on null
error from ajax request while uploading image via filemanager.
Config:
...
'modules' => [
'site' => [
'class' => 'app\modules\site\Module',
],
'user' => [
'class' => 'app\modules\user\Module',
'controllerNamespace' => 'app\modules\user\controllers\frontend',
'viewPath' => '#app/modules/user/views/frontend',
],
'admin' => [
'class' => 'app\modules\admin\Module',
'layout' => '#app/views/layouts/admin',
'modules' => [
'user' => [
'class' => 'app\modules\user\Module',
'controllerNamespace' => 'app\modules\user\controllers\backend',
'viewPath' => '#app/modules/user/views/backend',
],
'pages' => [
'class' => 'bupy7\pages\Module',
'controllerNamespace' => 'bupy7\pages\controllers\backend',
'controllerMap' => [
'manager' => [
'class' => 'bupy7\pages\controllers\backend\ManagerController',
],
],
],
'gallery' => [
'class' => 'sadovojav\gallery\Module',
'basePath' => '#webroot/galleries',
],
'filemanager' => [
'class' => 'pendalf89\filemanager\Module',
// Upload routes
'routes' => [
// Base absolute path to web directory
'baseUrl' => '',
// Base web directory url
'basePath' => '#webroot',
// Path for uploaded files in web directory
'uploadPath' => 'uploads',
],
// Thumbnails info
'thumbs' => [
'small' => [
'name' => 'Small',
'size' => [100, 100],
],
'medium' => [
'name' => 'Medium',
'size' => [300, 200],
],
'large' => [
'name' => 'Big',
'size' => [500, 400],
],
],
],
],
],
...
actionUpload() in Controller
public function actionUpload()
{
$model = new Mediafile();
$routes = $this->module->routes;
$rename = $this->module->rename;
$model->saveUploadedFile($routes, $rename);
Yii::$app->response->format = Response::FORMAT_JSON;
$tagIds = Yii::$app->request->post('tagIds');
if ($tagIds !== 'undefined') {
$model->setTagIds(explode(',', $tagIds));
}
$bundle = FilemanagerAsset::register($this->view);
if ($model->isImage()) {
$model->createThumbs($routes, $this->module->thumbs);
}
$response['files'][] = [
'url' => $model->url,
'thumbnailUrl' => $model->getDefaultThumbUrl($bundle->baseUrl),
'name' => $model->filename,
'type' => $model->type,
'size' => $model->file->size,
'deleteUrl' => Url::to(['file/delete', 'id' => $model->id]),
'deleteType' => 'POST',
];
return $response;
}
Checked in the model,
$this->file = UploadedFile::getInstance($this, 'file');
in saveUploadedFile() returns null instead of object.
The problem is that the function saveUploadedFile() is been executed, the file is saved and the record is created in the database, but it returns error.

How to use basic authentication for json requests and form authentication for html requests with Cakephp 3?

I need to filter json requests and allow basic authentication for those requests, while allowing only form authentication for html requests. When I filter the requests in my initialize function in AppController.php:
if ($this->request->is('json')) {
$this->loadComponent('Auth', [
'authorize' => ['Controller'],
'authenticate' => [
'Basic' => [
'fields' => ['username' => 'email', 'password' => 'password'],
'contain' => ['Districts']
]
]
]);
} else {
$this->loadComponent('Auth', [
'authorize' => ['Controller'],
'authenticate' => [
'Form' => [
'fields' => ['username' => 'email', 'password' => 'password'],
'contain' => ['Districts']
]
],
'loginAction' => [
'controller' => 'Users',
'action' => 'login'
],
'logoutRedirect' => [
'controller' => 'Users',
'action' => 'login'
]
]);
}
The json request creates and stores a session allowing the user to then access the rest of the site, including html requests because it has an authorized session. I struggled trying to find what was causing this and eventually found that you have to explicitly declare that the storage medium for the Basic Authentication method as 'Memory'. I'll post the correct code in my answer below.
This question is similar to this one for cakephp 2: CakePHP form authentication for normal requests with basic authentication for JSON
You have to explicitly declare that the Basic Authentication uses Memory for the storage medium, or else it will create a session. Here is the correct code:
if ($this->request->is('json')) {
$this->loadComponent('Auth', [
'authorize' => ['Controller'],
'authenticate' => [
'Basic' => [
'fields' => ['username' => 'email', 'password' => 'password'],
'contain' => ['Districts']
]
],
'storage' => 'Memory'
]);
} else {
$this->loadComponent('Auth', [
'authorize' => ['Controller'],
'authenticate' => [
'Form' => [
'fields' => ['username' => 'email', 'password' => 'password'],
'contain' => ['Districts']
]
],
'loginAction' => [
'controller' => 'Users',
'action' => 'login'
],
'logoutRedirect' => [
'controller' => 'Users',
'action' => 'login'
]
]);
}

Yii2 Email How to set sender name

i using Mailer to send email, so i have problem about sender name
This is my config
'mailer' => [
'class' => 'yii\swiftmailer\Mailer',
'useFileTransport' => false,
'messageConfig' => [
'charset' => 'UTF-8',
'from' => ['admin#app.com' => 'App Sender Name'],
],
'transport' => [
'class' => 'Swift_MailTransport',
],
],
So it's not work. I goto inbox and only email showed.
And i need show as
Example:
it's work when i update setFrom() method.
Ex: $mailer->setFrom(['email#app.com' => 'App Name']). And here is config Yii2 for send by PHP mail and with sender name
'mailer' => [
'class' => 'yii\swiftmailer\Mailer',
'useFileTransport' => false,
'messageConfig' => [
'charset' => 'UTF-8',
'from' => ['admin#app.com' => 'App Sender Name'],
],
'transport' => [
'class' => 'Swift_MailTransport',
],
],
and send email
Yii::$app->mailer->compose()
->setTo('client#email.com')
->setFrom(['admin#app.com' => 'App Name'])
....
Every component and sub-component in yii2 is configurable by dependency injection, this case is same, eg:
'transport' => [
'class' => 'Swift_SmtpTransport',
'host' => 'smtp.gmail.com',
'username' => 'noreply.yourcompany#gmail.com',
'password' => '123456',
'port' => '465',
'encryption' => 'ssl',
],

application configuration file path of yii2

I installed yii2 and then added gii to yii2 from this link.
return [
'bootstrap' => ['gii'],
'modules' => [
'gii' => 'yii\gii\Module',
// ...
],
// ...
];
I want to plce this code in application configuration file where it is located?
Application configuration file reside in: project_name/config/web.php
if (YII_ENV_DEV) {
$config['bootstrap'][] = 'gii';
$config['modules']['gii'] = [
'class'=>'yii\gii\Module',
'allowedIPs'=>['127.0.0.1','192.168.1.*'],
];
You will find a file web.php which is in in the config folder located at your root app folder, the file will contain something like the following:
$params = require __DIR__ . '/params.php';
$db = require __DIR__ . '/db.php';
$config = [
'id' => 'basic',
'name' => 'My Cool App',//If this line exists change it to your new app name otherwise add it.
'basePath' => dirname(__DIR__),
'bootstrap' => ['log'],
'aliases' => [
'#bower' => '#vendor/bower-asset',
'#npm' => '#vendor/npm-asset',
],
'components' => [
'request' => [
// !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
'cookieValidationKey' => '_4wmrZYaMY7joBAFHrXKpEIFvs9m9S_I',
],
'cache' => [
'class' => 'yii\caching\FileCache',
],
'user' => [
'identityClass' => 'app\models\User',
'enableAutoLogin' => true,
],
'errorHandler' => [
'errorAction' => 'site/error',
],
'mailer' => [
'class' => 'yii\swiftmailer\Mailer',
// send all mails to a file by default. You have to set
// 'useFileTransport' to false and configure a transport
// for the mailer to send real emails.
'useFileTransport' => true,
],
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
'class' => 'yii\log\FileTarget',
'levels' => ['error', 'warning'],
],
],
],
'db' => $db,
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
],
],
],
'params' => $params,
];
if(YII_ENV_DEV) {
// configuration adjustments for 'dev' environment
$config['bootstrap'][] = 'debug';
$config['modules']['debug'] = [
'class' => 'yii\debug\Module',
// uncomment the following to add your IP if you are not connecting from localhost.
//'allowedIPs' => ['127.0.0.1', '::1'],
];
$config['bootstrap'][] = 'gii';
$config['modules']['gii'] = [
'class' => 'yii\gii\Module',
// uncomment the following to add your IP if you are not connecting from localhost.
//'allowedIPs' => ['127.0.0.1', '::1'],
];
}
return $config;
Notice I've added a line: 'name' => 'My Cool App',
Hope this helps.

Yii2 SwiftMailer sending email via remote smtp server (gmail)

I want to send emails via my gmail account.
My mailer config:
[
'class' => 'yii\swiftmailer\Mailer',
'useFileTransport' => false,//set this property to false to send mails to real email addresses
'transport' => [
'class' => 'Swift_SmtpTransport',
'host' => 'smtp.gmail.com',
'username' => 'my#gmail.com',
'password' => 'pass',
'port' => '587',
'encryption' => 'tls',
],
]
I wrote command MailController:
<?php
namespace app\commands;
use yii\console\Controller;
use Yii;
/**
* Sanding mail
* Class MailController
* #package app\commands
*/
class MailController extends Controller
{
private $from = 'my#gmail.com';
private $to = 'to#gmail.com';
public function actionIndex($type = 'test', $data = null)
{
Yii::$app->mailer->compose($type, ['data' => $data])
->setFrom($this->from)
->setTo($this->to)
->setSubject($this->subjects[$type])
->send();
}
}
When I'm trying to run: php yii mail
I get: sh: 1: /usr/sbin/sendmail: not found
But why it requires sendmail if I want just SMTP connection to smtp.gmail.com?
I think you have configured the mailer wrongly. Because it is still using the default mail function. From the documentation the configuration should be like below. The mailer should be inside components.
'components' => [
...
'mailer' => [
'class' => 'yii\swiftmailer\Mailer',
'transport' => [
'class' => 'Swift_SmtpTransport',
'host' => 'smtp.gmail.com',
'username' => 'username',
'password' => 'password',
'port' => '587',
'encryption' => 'tls',
],
],
...
],
One more suggestion is to use port "465" and encryption as "ssl" instead of port "587", encryption "tls".
Yii2 Has different config files for web and console works. So you need to config both of them. Regarding this issue, I had to make mail config file (for example mailer.php) and include it in both config files (web.php & console.php) like:
'components' => [
...
'mailer' => require(__DIR__ . '/mailer.php'),
...
],
Might be useful for someone as reference:
'mailer' => [
'class' => 'yii\swiftmailer\Mailer',
'viewPath' => '#common/mail',
'useFileTransport' => false,
'transport' => [
'class' => 'Swift_SmtpTransport',
'host' => 'smtp.gmail.com',
'username' => 'username',
'password' => 'password',
'port' => 587,
'encryption' => 'tls',
'streamOptions' => [
'ssl' => [
'allow_self_signed' => true,
'verify_peer' => false,
'verify_peer_name' => false,
],
]
],
]