= Yii 2 Console ==
== Scheduled Console Action (Emailing) ==
Create command in Yii console (''[app]/commands/MailController.php''):
namespace app\commands;
use yii\console\Controller;
class MailController extends Controller {
public function actionSend() {
// Code here to send the mail
// Example details: http://www.yiiframework.com/doc-2.0/yii-swiftmailer-mailer.html
Yii::$app->mailer->compose('contact/html', ['contactForm' => $form])
->setFrom('from@domain.com')
->setTo($form->email)
->setSubject($form->subject)
//->setTextBody($this->body) // optionally set data here
->send();
}
...
}
Run this command from CLI:
C:\WAMP\WWW\ACME\>yii mail/send
Run a crontab job calling a task in Yii2. Eg: ''/etc/cron.daily/send-email''
#!/bin/bash
## script: /etc/cron.daily/send-email
##
#-----------------------------
# Define Yii2 Source Directory
#-----------------------------
SOURCEDIR="/var/www/acme"
#-----------------------------
# Run Yii2 Action
#-----------------------------
/usr/bin/php -f $SOURCEDIR/yii mail/send
## Log operation
echo "Daily Email Reminder Completed: $(date)" >> /var/log/yii2.log
#mail root@localhost -s "Daily Email Reminder Completed"
Or create task directly in ''/etc/crontab''. For example, run a command every 5 min:
*/5 * * * * /var/www/[yiiroot]/yii mail/send
== Running Console Action from Web View ==
Let us assume the following command controller for our console action:
...
class EmailNotificationController extends Controller
{
public function actionSendEmail($dstEmail, $workOrderId)
{
...
}
}
Console actions are typically called directly from the command line. Eg: For a command ''send-email'' in console controller ''[app]/commands/email-notification'', we run it at the console as follows:
$ yii email-notification/send-email dstEmail='info@acme.com' workOrderId=1
Sometimes we need to call this command from the web side, in order to avoid duplicate functionality, to automate the process, or simply when a command shell is not available with a hosting provider.
=== Method 1 ===
To enable this, create a new action in a web controller to call the console action:
use app\commands\EmailNotificationController;
...
class WorkOrderController extends Controller
{
...
public function actionSendEmail($id)
{
// use app\commands\EmailNotificationController; // add this include to file
// "test" is a placeholder with no effect (required though)
$command = new EmailNotificationController("test", "test");
$command->actionSendEmail('info@acme.com', $id); // $dstEmail, $workOrderId
...
Yii::$app->session->setFlash('success', "Sent Email");
return $this->redirect(['view', 'id' => $id]);
}
}
Call the action from the view as usual:
...
= Html::a(Yii::t('app', 'Notify by Email'),
['work-order/send-email', 'id' => $model->id],
['class' => 'btn btn-primary'])
?>
...
Define STDIN and STDOUT in the console action:
namespace app\commands;
use Yii;
use yii\console\Controller;
use app\models\Email;
use app\models\WorkOrder;
use yii\helpers\Console;
/**
*
*/
class EmailNotificationController extends Controller
{
/**
* This command send email message.
* @param string $message the message to be echoed.
*/
public function actionSendEmail($dstEmail, $workOrderId)
{
// NOTE: Define these for the console app to work correctly
// when called from web controller.
defined('STDIN') or define('STDIN', fopen('php://stdin', 'r'));
defined('STDOUT') or define('STDOUT', fopen('php://stdout', 'w'));
...
}
}
See: [[http://stackoverflow.com/questions/10151887/how-to-call-a-console-command-in-web-application-action-in-yii]]
=== Method 2 ===
Alternatively, you can use a component to do similar work:
// File : [app]/common/components/General.php
// Author: sadaa
// Source: https://github.com/yiisoft/yii2/issues/6853
namespace common\components;
use Yii;
use yii\base\Component;
use yii\console\Application;
class General extends Component
{
/**
* Create and return an application instance
* if the console app doesn't exist we create a new instance
* otherwise, it returns the existing instance
*
* @return null|\yii\base\Module|Application
*/
public static function switchToConsoleApp()
{
$config = self::getConsoleConfig();
if (!$consoleApp = Yii::$app->getModule($config['id'])) {
$consoleApp = new Application($config);
}
// Assuming that switching apps only happens when making console commands through the web app,
// we have to redefine STDOUT to trick the console output into going straight to the web output
define('STDOUT', fopen('php://output', 'w'));
return $consoleApp;
}
public static function runConsoleActionFromWebApp($action, $params = [])
{
$webApp = Yii::$app;
$consoleApp = self::switchToConsoleApp();
$result = ($consoleApp->runAction($action, $params) == \yii\console\Controller::EXIT_CODE_NORMAL);
Yii::$app = $webApp;
return $result;
}
public static function getConsoleConfig()
{
return ArrayHelper::merge(
require(Yii::getAlias('@common/config/main.php')),
require(Yii::getAlias('@common/config/main-local.php')),
require(Yii::getAlias('@console/config/main.php')),
require(Yii::getAlias('@console/config/main-local.php'))
);
}
}
In any web controller, we call the console action as follows:
// Example usage within any web controller
SiteController extends \yii\web\Controller
{
public function actionRbacLoad()
{
General::runConsoleActionFromWebApp('rbac/load');
}
public function actionMigrate()
{
General::runConsoleActionFromWebApp('migrate',
['migrationPath' => '@console/migrations/', 'interactive' => false]
);
}
}
=== Method 3 ===
/**
* Class ConsoleAppHelper
* @package app\components
*/
class ConsoleAppHelper
{
public static function runAction( $route, $params = [ ], $controllerNamespace = null )
{
$origApp = \Yii::$app;
// fcgi doesn't have STDIN and STDOUT defined by default
defined( 'STDIN' ) or define( 'STDIN', fopen( 'php://stdin', 'r' ) );
defined( 'STDOUT' ) or define( 'STDOUT', fopen( 'php://stdout', 'w' ) );
/** @noinspection PhpIncludeInspection */
$config = require( \Yii::getAlias( '@app/config/console.php' ) );
$consoleApp = new ConsoleApplication( $config );
if (!is_null( $controllerNamespace )) {
$consoleApp->controllerNamespace = $controllerNamespace;
}
try {
// use current connection to DB
\Yii::$app->set( 'db', $origApp->db );
ob_start();
$exitCode = $consoleApp->runAction(
$route,
array_merge( func_get_arg( 1 ), [ 'interactive' => false, 'color' => false ] )
);
$result = ob_get_clean();
\Yii::trace( $result, 'console' );
} catch ( \Exception $e ) {
\Yii::warning( $e->getMessage() . ' in ' . $e->getFile() . ' on line ' . $e->getLine(), 'console' );
$exitCode = 1;
}
\Yii::$app = $origApp;
return $exitCode;
}
}
Call it as:
use app\commands\EmailNotificationController;
use app\components\ConsoleAppHelper;
...
class WorkOrderController extends Controller
{
...
public function actionSendEmail($id)
{
// use app\components\ConsoleAppHelper; // add this include to file
// params: $dstEmail, $workOrderId
ConsoleAppHelper::runAction( 'email-notification/send-mail', ['info@acme.com', $id] );
...
Yii::$app->session->setFlash('success', "Sent Email");
return $this->redirect(['view', 'id' => $id]);
}
}
See: [[https://github.com/yiisoft/yii2/issues/1764]]