How to separate each action in a different file in Yii2

Viewed 254

I'm new in Yii2 framework. To give structure to my web application, I want to put each controller in a subfolder and make a separate controller for each action in each subfolder. Like that one!

controllers
        **User**
            IndexController
            EditController
            UpdateController
        
        **Profile**
            IndexController
            EditController
            UpdateController

How can I arrange that in Yii2. thanks in advance

2 Answers

Well your example is right.

controllers/user/IndexController.php

views/user/index/index.php

Then in IndexController/EditController/UpdateController you have actionIndex and if you run domain.com/user/index or domain.com/user/edit it will execute actionIndex in current controller (IndexController or EditController)

domain.com/user/index = domain.com/user/index/index

and 

domain.com/user/edit = domain.com/user/edit/index

Not sure if there are other more effective ways, but one that works would be the following.

Note: This example assumes that you're using https://github.com/yiisoft/yii2-app-advanced but it can work for the basic app also, just changing the namespaces.

So, let's say you say we have a controller, and we want to store some of its actions into different php files.

<?php

// frontend\controllers\SiteController.php

namespace frontend\controllers;

use yii\web\Controller;

class SiteController extends Controller {

  public function actions() {
    return [
        'error' => [
            'class' => 'yii\web\ErrorAction',
        ],
        'captcha' => [
            'class' => 'yii\captcha\CaptchaAction',
            'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
        ],
        'hello-world' => [
            'class' => 'frontend\controllers\site\HelloWorldAction',
        ],
    ];
  }

  public function actionIndex() {
      // ...
  }

So you can see we've got 3 external actions and one internal one.

The first two ones, are framework's tools for Error page and Captcha generation, actually they've inspired my answer.

And the third one, is defined by us:

'hello-world' => [
   'class' => 'frontend\controllers\site\HelloWorldAction',
],

So we've named the action and we created our new action class into a separate directory.

<?php

// frontend\controllers\site\HelloWorldAction.php

namespace frontend\controllers\site;

use yii\base\Action;

class HelloWorldAction extends Action {

  public function run($planet='Earth') {
    return $this->controller->render('hello-world', [
        'planet'=>$planet,
    ]);
  }

}

And last, our view:

<?php

// frontend\views\site\hello-world.php

/* @var $this yii\web\View */

use yii\helpers\Html;

$this->title = 'Hello world page';
?>

<h1>Hello world!</h1>

<p>We're on planet <?php echo Html::encode($planet); ?></p>

And seeing it in action:

Testing on localhost

Update

After posting the answer I realized that maybe you could benefit from another technique also.

The previous answer is good if you want to do just that: Extract actions into individual files.

But, if your application will be of certain size, maybe you should consider using Modules.

You can create them manually or generate them with Gii:

Yii2 module generation

And once generated, include it in your config:

<?php
    ......
    'modules' => [
        'profile' => [
            'class' => 'frontend\modules\profile\Module',
        ],
    ],
    ......

Modules do just that, group application logic into one directory, controllers, models, views, components, etc.

Two more tips:

Now to access your module, simply visit http://www.your-site.local/profile/default/index, as you can see, it goes like module/controller/action.

And if you want to generate links to actions inside modules, you would do:

<?php
echo Url::to([
    'profile/default/index',
    'param'=>'value',
]);
?>

Again as you can see we're using module/controller/action as the route.

Last thing, if you're inside a module, let's say profile/picture/edit, and you want to link to Contact page from SiteController, you would do:

<?php
echo Url::to([
    '//site/contact', 
    'param'=>'value',
]);
?>

Note the double slash // at the beginning of the route. Without it, it will generate the url to the current module profile/site/contact.

Related