Antonín Slejška
Antonín Slejška

Reputation: 2040

Yii2: Run a web action in a console controller

Is it possible to run a web action in a console controller?

In a web controller (yii\web\Controller) I have an action which I would like to run as a cron job. But if I try to run it in a console controller (yii\console\Controller):

Yii::$app->runAction('controller/action');

then I receive the following error message:

Error: Unknown command "controller/action".

Upvotes: 3

Views: 5175

Answers (3)

Nick Tsai
Nick Tsai

Reputation: 4149

Run a web action in a console controller:

Yii::$app->controllerNamespace = "app\controllers";
Yii::$app->runAction('controller/action');

Assign controllerNamespace before running the web action from console.


In addition, disable enableCsrfValidation for the web action:

public function beforeAction($action)
{    
    if ($action->id == 'action') {
        $this->enableCsrfValidation = false;
    }    

    return parent::beforeAction($action);
}

The 'action' ID could be replaced with your current web action ID.

Upvotes: 3

Antonín Slejška
Antonín Slejška

Reputation: 2040

The solution with cURL.

In the web controller have to be disabled the CSRF validation:

public function beforeAction() {
    if ($this->action->id == 'export') {
       Yii::$app->controller->enableCsrfValidation = false;
   }
   return true;
}

The cURL commands in the console Controller can look e.g. like this:

$ch = curl_init();

$options = array(
    CURLOPT_URL             => $url,
    CURLOPT_REFERER         => $url,
    CURLOPT_FOLLOWLOCATION  => 1,
    CURLOPT_RETURNTRANSFER  => 1,
    CURLOPT_COOKIESESSION   => true,
    CURLOPT_COOKIEJAR       => 'curl-cookie.txt',
    CURLOPT_COOKIEFILE      => '/var/www/yii/frontend/web/tmp',
    CURLOPT_CONNECTTIMEOUT  => 120,
    CURLOPT_TIMEOUT         => 120,
    CURLOPT_MAXREDIRS       => 10,
    CURLOPT_USERAGENT       => "Dark Secret Ninja/1.0",
    CURLOPT_POST            => 1,
    CURLOPT_POSTFIELDS      => "LoginForm[username]=".$username.
        "&LoginForm[password]=".$password.
        "&LoginForm[rememberMe]=1",
    CURLOPT_SSL_VERIFYPEER  => false,
);
curl_setopt_array( $ch, $options );

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);   //get status code

if ( $httpCode != 200 ){
    echo "Return code is {$httpCode} \n"
        .curl_error($ch);
} else {
    echo htmlspecialchars($response);
}
curl_close($ch);

Upvotes: 1

Rober Diaz
Rober Diaz

Reputation: 38

Sorry, I did not understand the context of the question.

As @soju says, you should find a way to do it using CURL, but there is a way.

$config = \yii\helpers\ArrayHelper::merge(
            require(Yii::getAlias('@common').'/config/main.php'),
            require(Yii::getAlias('@common').'/config/main-local.php'),
            require(Yii::getAlias('@frontend').'/config/main.php'),
            require(Yii::getAlias('@frontend').'/config/main-local.php')
        );

$web_application = new \yii\web\Application($config);
$web_application->runAction('/site/index',['param1' => 1,'param2' => 2]);

You should be aware that the controller works with their behaviors, then the AccessControl could prevent the execution

Upvotes: 2

Related Questions