I have the following config file
common/main-local.php
return [
'components' => [
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=aishwariya_basic2',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
],
// 'db' => $db,
'db2' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=aishwariya_basic',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
],
'mailer' => [
'class' => 'yii\swiftmailer\Mailer',
'viewPath' => '#common/mail',
],
// autoloading model and component classes
'import'=> [
'class' => 'yii2-widget-linkpager',
'application.extensions.MyLinkPager.*',
],
],
];
Admincontroller
namespace frontend\controllers;
use Yii;
use frontend\models\Site_login;
use frontend\models\EntryForm_model;
use frontend\models\Asal_page_model;
use frontend\models\Interest_page_model;
use frontend\models\Return_page_model;
use frontend\models\Daily_report_model;
use frontend\models\Changepassword;
use yii\base\InvalidParamException;
use yii\web\BadRequestHttpException;
use yii\web\Controller;
use yii\filters\VerbFilter;
use yii\filters\AccessControl;
use yii\helpers\ArrayHelper;
use yii\db\Query;
class AdminController extends Controller
{
/**
* #inheritdoc
*/
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'only' => ['index', 'signup'],
'rules' => [
[
'actions' => ['index'],
'allow' => true,
'roles' => ['?'],
],
[
'actions' => ['settings','changepassword'],
'allow' => true,
'roles' => ['#'],
],
],
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'logout' => ['post'],
],
],
];
}
/**
* #inheritdoc
*/
public function actions()
{
return [
'error' => [
'class' => 'yii\web\ErrorAction',
],
'captcha' => [
'class' => 'yii\captcha\CaptchaAction',
'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
],
];
}
#####Action index code starts here
public function actionIndex()
{
$this->layout = 'admin';
$my2DbConn = Yii::$app->db;
$model = new Site_login();
if ($model->load(Yii::$app->request->post()) )
{
if ($model->validate()) {
$url = Yii::$app->getUrlManager()->getBaseUrl()."/admin/search";
return $this->redirect($url);
}
}
return $this->render('index', ['model' => $model]);
}
Site controller
public function actionInitial()
{
$this->layout = 'site';
$my2DbConn = Yii::$app->db2;
$model=new Initial_model();
if ($model->load(Yii::$app->request->post()))
{
}
return $this->render('initial',['model'=>$model]);
}
I would like to change the database belongs to controller. Please give me some help. I have used two db but it tooks first db file.
You can configure more then a db in config
return [
'components' => [
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=testdb',
'username' => 'demo',
'password' => 'demo',
],
'db2' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=testdb2',
'username' => 'demo2',
'password' => 'demo2',
],
],
];
and obtain your db (this is if you want use direct command in controller and not for activeRecord)
class yourController extends \yii\web\Controller
{
public function actionYourAction()
{
...
$my2DbConn = Yii::$app->db2;
....
}
Or you can manage programmatically with the proper setting
If for your model (like you have in your code ) you want to use a different database connection other than the db component, you should override the getDb() method in your related ActiveRecord MODEL (see the doc .. link at the bottom):
class YourModel extends ActiveRecord // eg: Initial_model
{
// ...
public static function getDb()
{
// use the "db2" application component
return \Yii::$app->db2;
}
}
and not assign $my2DbConn = Yii::$app->db; in controller this is for createCommand (direct sql commend) and not for activeRecord like you need ..
see this guide http://www.yiiframework.com/doc-2.0/guide-db-active-record.html or this reference for related param http://www.yiiframework.com/doc-2.0/yii-db-connection.html
Related
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.
I've found a lot of answers on how to create Access Control that requires login to all controllers and actions.
The following post shows how I did all controllers require login:
Yii2 require all Controller and Action to login
I've used the code below under my components:
'as beforeRequest' => [
'class' => 'yii\filters\AccessControl',
'rules' => [
[
'allow' => true,
'actions' => ['login', 'error'],
],
[
'allow' => true,
'roles' => ['#'],
],
]
],
But, I want to add some exceptions to it. Some controllers need to have some actions visible to Guest.
I've tried to use this code inside my behaviors on ReportsController:
'access' => [
'class' => AccessControl::className(),
'rules' => [
[
'allow' => true,
'actions' => ['share'],
'roles' => ['?'],
],
],
]
Still get redirected to login.
I'm trying to to make actionShare($param) {} public to guests.
What am I missing?
Thanks for all your help!
First execute
yii migrate --migrationPath=#yii/rbac/migrations
from command prompt to create RBAC table in data base.
Then create RbacController in component folder
namespace app\components;
use yii;
use yii\web\Controller;
use yii\filters\AccessControl;
class RbacController extends Controller
{
public function RbacRule($modules = false)
{
$rules = false;
if ($modules){
$rules = [
'allow' => true,
'roles' => ['#'],
'matchCallback' => function ($rule, $action) {
$module = Yii::$app->controller->module->id;
$action = Yii::$app->controller->action->id;
$controller = Yii::$app->controller->id;
$route = "/$module/$controller/$action";
$post = Yii::$app->request->post();
if (\Yii::$app->user->can($route)) {
return true;
}
}
];
}else{
$rules = [
'allow' => true,
'roles' => ['#'],
'matchCallback' => function ($rule, $action) {
//$module = Yii::$app->controller->module->id;
$action = Yii::$app->controller->action->id;
$controller = Yii::$app->controller->id;
$route = "/$controller/$action";
$post = Yii::$app->request->post();
if (\Yii::$app->user->can($route)) {
return true;
}
}
];
}
return $rules;
// return true;
}
}
then extend to your controller using this RbacController instead of controller.
use app\components\RbacController;
class AdminController extends RbacController
{
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
// [
// 'actions' => ['login', 'logout'],
// 'allow' => true,
// 'roles' => ['?'],
// ],
parent::RbacRule(),
],
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'delete' => ['post'],
'bulk-delete' => ['post'],
],
],
];
}
.......
}
If your controller is inside Modules folder then you have to use
parent::RbacRule(TRUE) instead of parent::RbacRule(),
I have a problem. I did a login form with all by default (bcrypt), but I need to do it with sha256 password in my database. How can I do it?
This is my AppController:
public function initialize()
{
$this->loadComponent('Flash');
$this->loadComponent('Auth', [
'authenticate' => [
'Form' => [
'fields' => [
'username' => 'nombre',
'passwordHasher' => array(
'hashType' => 'sha256',
'className' => 'password'
)
]
]
],
'loginAction' => [
'controller' => 'Users',
'action' => 'login'
],
'loginRedirect' => [
'controller' => 'Home',
'action' => 'index'
]
]);
// Allow the display action so our pages controller
// continues to work.
$this->Auth->allow(['display']);
}
And usersController:
public function login()
{
if ($this->request->is('post')) {
$user = $this->Auth->identify();
if ($user) {
$this->Auth->setUser($user);
return $this->redirect($this->Auth->redirectUrl());
}
$this->Flash->error('El usuario o contraseña no es válido.');
}
}
I have to say that no errors are showed, but it shows that user or password are incorrect.
Right now I am working on project where we need facebook and twitter login.
And I have also configure the login in my project but now its not authenticate with simple username and password.
This is AppController.php
class AppController extends Controller
{
public function initialize()
{
$this->loadComponent('Flash');
$this->loadComponent('Auth', [
'loginRedirect' => [
'controller' => 'Users',
'action' => 'index'
],
'logoutRedirect' => [
'controller' => 'Users',
'action' => 'login'
],
'authenticate' => [
'ADmad/HybridAuth.HybridAuth'
]
]);
}
}
Its working with only facebook and twitter login,and please let me know how to store user in database after successful login in fb or twitter.
Change above function to this.
public function initialize()
{
$this->loadComponent('Flash');
$this->loadComponent('Auth', [
'authenticate' => [
'Form',
'ADmad/HybridAuth.HybridAuth'
],
'loginRedirect' => [
'controller' => 'Users',
'action' => 'index',
'plugin' => false
],
'logoutRedirect' => [
'controller' => 'Users',
'action' => 'login',
'plugin' => false
]
]);
}
The point here is: just add "Form" under "authenticate".
CakePHP can handle many login types simultaneously.
To store your users in the database just follow the plugin's instructions to set up the users and social_profiles tables.
Then simply add your regular user logic (UsersController + login.ctp, etc, etc).
Here's how I load the Auth component to achieve this:
$this->loadComponent('Auth', [
'authenticate' => [
'Form' => [
'fields' => [
'username' => 'email',
'password' => 'password'
],
],
'ADmad/HybridAuth.HybridAuth' => [
'fields' => [
'provider' => 'provider',
'openid_identifier' => 'openid_identifier',
'email' => 'email'
],
'profileModel' => 'ADmad/HybridAuth.SocialProfiles',
'profileModelFkField' => 'user_id',
'hauth_return_to' => null
],
],
]);
public function behaviors()
{
return [
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'delete' => ['post'],
],
],
'access' => [
'class' => AccessControl::className(),
'only' => ['create', 'update', 'delete', 'view', 'index'],
'rules' => [
// allow authenticated users
[
'allow' => true,
'roles' => ['#'],
],
// everything else is denied by default
],
],
[
'class' => TimestampBehavior::className(),
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => ['create_time', 'update_time'],
ActiveRecord::EVENT_BEFORE_UPDATE => ['update_time'],
],
],
];
}
Above code is for my controller behavior function. While creating or updating, 'create_time' and 'update_time' fields are not getting updated by current time. Type of those fields are set to datetime. Please need your help.
You have to declare it in the behaviors method of your model.
To use TimestampBehavior, insert the following code to your ActiveRecord class
public function behaviors()
{
return [
'class' => TimestampBehavior::className(),
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => ['create_time', 'update_time'],
ActiveRecord::EVENT_BEFORE_UPDATE => ['update_time'],
],
];
}
Try this, it works for me:
use yii\db\Expression;
...
[
'class' => TimestampBehavior::className(),
'updatedAtAttribute' => 'update_time',
'value' => new Expression('NOW()'),
],
You can also use
'value' => date('Y-m-d H:i:s')
if you would like to use the PHP datetime.
I used new Expression('NOW()') to store current timestamp. But It does't store the date based on current timezone. Instead it stores based on server time.
I just used normal php date function to solve this.
eg :
use yii\behaviors\TimestampBehavior;
use yii\db\Expression;
public function behaviors()
{
return [
'timestamp' => [
'class' => 'yii\behaviors\TimestampBehavior',
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => ['created_at', 'updated_at'],
ActiveRecord::EVENT_BEFORE_UPDATE => ['updated_at'],
],
'value' => date('Y-m-d H:i:s'),
],
];
}
You must also add the value and use the class Expression
use yii\behaviors\TimestampBehavior;
use yii\db\Expression;
public function behaviors()
{
return [
'timestamp' => [
'class' => 'yii\behaviors\TimestampBehavior',
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => ['created_at', 'updated_at'],
ActiveRecord::EVENT_BEFORE_UPDATE => ['updated_at'],
],
'value' => new Expression('NOW()'),
],
];
}