Yii 2 Setup and Configuration

Install the following:

1. Download from: Yii Framework

2. Get Yii2 themes from: Theme Factory

3. Get Bootstrap themes from: BootSwatch

4. Get Composer from: GetComposer

Install Composer
  • Install composer (from https://getcomposer.org).
  • Update composer. Make sure all composercomponents are up-to-date:
    C:\> php C:\ProgramData\ComposerSetup\bin\composer.phar global update fxp/composer-asset-plugin --no-plugins 
    C:\> composer global require "fxp/composer-asset-plugin:~1.1.1"
    C:\> php C:\ProgramData\ComposerSetup\bin\composer.phar update yiisoft/yii2 yiisoft/yii2-composer bower-asset/jquery.inputmask
Install Auth Token for Composer (requires Authentication to GitHub)

To solve issues with API rate limiting on GitHub while using Composer, you need to have GitHub credentials.

  • Login (or signup for an free account) at GitHub.
  • Go to Account > Settings > Personal access tokens (https://github.com/settings/applications) and delete the previous token generated during the installation of yii2.
  • Create a new token. NOTE: Save it somewhere, because it is not going to be readable afterwards. Eg: Name it yii2 composer with access scope public_repo.
  • Register the token with Composer:
    C:\> composer config -g github-oauth.github.com <oauthtoken> 

Alternatively: Enter credentials in this file: C:\Users\< username >\AppData\Roaming\Composer\auth.json

{
    "http-basic": {},
    "github-oauth": {
        "github.com": "<oauthtoken>"}
}

Example:

{
    "http-basic": {},
    "github-oauth": {
        "github.com": "8dabf7def512b794607a6642806bd737227c8bc0"}
}
Install Yii

Run composer command to install Yii.

  • Install pre-requisites:
    • $php composer.phar global require "fxp/composer-asset-plugin:^1.4.2"
  • Choose one of these to install, either the basic or advanced application template:
    • $php composer.phar create-project yiisoft/yii2-app-basic basic 2.0.15
    • $php composer.phar create-project yiisoft/yii2-app-advanced advanced 2.0.15

Note that you may be prompted to enter your GitHub username and password during the installation process. This is normal. Just enter them and continue. If you have not done so already, get a GitHub auth token.

Upgrade Yii
  • Run command in Yii root folder (where yii command resides):
    $ composer update
  • Follow upgrade instructions if necessary: https://github.com/yiisoft/yii2/blob/master/framework/UPGRADE.md
  • Troubleshooting: perform these steps before upgrading:
    $ composer self-update    // to have the latest composer
    $ composer global update  // to make sure latest fxp is used
    $ composer clear-cache    // to make sure success is not because of cache
    $ composer global require "fxp/composer-asset-plugin:^1.4.2" --no-plugins
    $ composer require "yiisoft/yii2:~2.0.15" --update-with-dependencies
    $ composer update yiisoft/yii2 yiisoft/yii2-composer bower-asset/jquery.inputmask

Edit composer.json as follows. Move extra.asset-installer-paths to config.fxp-asset.installer-paths instead:

    "extra": {
        "yii\\composer\\Installer::postCreateProject": {
            "setPermission": [
                {
                    "runtime": "0777",
                    "web/assets": "0777",
                    "yii": "0755"
                }
            ],
            "generateCookieValidationKey": [
                "config/web.php"
            ]
        },
        // Remove
        //"asset-installer-paths": {
        //    "npm-asset-library": "vendor/npm",
        //    "bower-asset-library": "vendor/bower"
        //}
    }
    "config": {
        "process-timeout": 1800,
        // Add
        "fxp-asset": {
            "installer-paths": {
                "npm-asset-library": "vendor/npm",
                "bower-asset-library": "vendor/bower-asset"
            }
        }
    }

Upgrade codeception component (remove yii2-codeception):

    "require-dev": {
        // Remove
        //"yiisoft/yii2-codeception": "*",
 
        // Add
        "codeception/base": "^2.2.3",
        "codeception/codeception": "2.3.*",
        "codeception/specify": "*",
        "codeception/verify": "*"
    }

Yii2 expects Bower and NPM packages to be installed to vendor/bower and vendor/npm folders respectively. So, to use asset-packagist it's necessary to add aliases in web.php:

$config = [
    ...
    'aliases' => [
        '@bower' => '@vendor/bower-asset',
        '@npm'   => '@vendor/npm-asset',
    ],
    ...
];
Initial Configuration

Prepare config files to support a 'local' (non-version controlled) copy.

For the advanced app:

  • Generate the local config files. Run this command at project root: [app]$ init.
  • Find config files in common, frontend, backend, and console.

For the basic app:

  • db.php would need db-local.php
  • console.php would need console-local.php (optional)
  • params.php would need params-local.php
  • web.php would need web-local.php

The local versions would be empty, but you can add parameters to override the respective settings:

<?php
return [
];

For basic app only: Edit the following to support local copies. [app]/config/web.php, [app]/config/console.php, and [app]/config/test.php:

//$params = require(__DIR__ . '/params.php');
$params = array_merge(
    require(__DIR__ . '/params.php'),
    require(__DIR__ . '/params-local.php')
);
 
//$db = require(__DIR__ . '/db.php');
$db = array_merge(
    require(__DIR__ . '/db.php'),
    require(__DIR__ . '/db-local.php')
);
...
$config = [
   ...
   'components' => [
       'db' => $db, //require(__DIR__ . '/db.php'),
   ],
];   

For basic app only: [app]/web/index.php:

...
//$config = require(__DIR__ . '/../config/web.php');
$config = yii\helpers\ArrayHelper::merge(
    require(__DIR__ . '/../config/web.php'),
    require(__DIR__ . '/../config/web-local.php')
);
...

For basic app only: Required for console and migration commands, edit file [app]/yii to support local copies:

...
//$config = require(__DIR__ . '/config/console.php');
$config = yii\helpers\ArrayHelper::merge(
    require(__DIR__ . '/config/console.php'),
    require(__DIR__ . '/config/console-local.php')
);
...

Database Config

Edit the following configuration files.

/[app]/config/db.php or /[app]/common/config/db.php

return [
    'class'       => 'yii\db\Connection',
    'dsn'         => 'mysql:host=localhost;dbname=acme_dbname',
    'username'    => 'acme_dbusername',
    'password'    => 'acme_dbpassword',
    'charset'     => 'utf8',
    'tablePrefix' => 'main_',
];

Params Config

/[app]/config/params.php or /[app]/common/config/params.php

return [
    'appId'                         => 'app_intranet',
    'appName'                       => 'Intranet',
    'appNameShort'                  => 'Intranet',
    'companyName'                   => 'Acme, Inc.',
    'companyNameShort'              => 'Acme',
    'companyAddress'                => '123 Main St, Maplewood, VA 12345, United States',
    'companyEmail'                  => 'info@acme.com',
    'companyPhone'                  => '800-123-ACME',
    'companyFax'                    => '800-123-ACME',
    'companyWebsite'                => 'http://www.acme.com',
    'companyWebsiteSecure'          => 'https://secure.acme.com',
    'adminEmail'                    => 'admin@acme.com',
    'supportEmail'                  => 'support@acme.com',
    'debugEmail'                    => 'support@acme.com',
    'urlWebmail'                    => 'https://outlook.office365.com/owa/?realm=acme.com',
    'urlSocialFacebook'             => 'https://www.facebook.com/acme',
    'urlSocialYoutube'              => 'http://www.youtube.com/user/acme',
    'urlSocialTwitter'              => 'https://twitter.com/acme',
    'user.passwordResetTokenExpire' => 3600,
    'isSignupApprovalRequired'      => false, // allows user to signup and login right away
    //'isSignupApprovalRequired'    => true,  // requires sending email to admin to request signup approval
    'timezone'                      => 'America/New_York',  // Must be a valid PHP timezone.  See: http://php.net/manual/en/timezones.php
    'siteLayout'                    => 'default',  // ['full', 'default_white', 'default_gray', 'default']
    'authorizenetAPILoginId'        => "YOURLOGIN",
    'authorizenetTransactionKey'    => "YOURKEY",
    'authorizenetTestMode'          => true,
    'authorizenetSandbox'           => true,
 
    //-----------------------------------
    // Site Message of the Day (MOTD)
    //-----------------------------------
    // --- Hurricane mesg ---
    //'appMOTD'                       => '<div class="col-md-6">
    //    <h3>NOTE<h3> Due to a hurricane hitting our area, 
    //    the office will be closed  We apologize for the inconvenience. </div>
    //    <div class="col-md-6">
    //    <h3>NOTA</h3> Debido al huracán afectando nuestra área, la oficina estará cerrada.  
    //    Nuestras disculpas por este inconveniente.</div>',  
    //  --- Phone Line Down message ---
    //'appMOTD'                       => '<h3>NOTE</h3> Our phone lines are not available due 
    //    to a nationwide phone provider outage.  We apologize for the inconvenience.', 
    //  --- Memorial Day message ---
    //'appMOTD'                        => '<h3>Memorial Day Closure</h3> Our offices will be 
    //    closed in observance of the Memorial Day holiday. We will resume normal hours on Monday. ',
    //  --- US Independence/4th July message
    //'appMOTD'                        => '<h3>US Independence Day Closure</h3> Our offices 
    //  will be closed July 4, in observance of the US Independence Day holiday. 
    //  We will resume normal hours on July 5. ',  // site Message of the Day
    //  --- Labor Day message ---
    //'appMOTD'                        => '<h3>Labor Day Closure</h3> Our offices will be 
    //   closed in observance of the Labor Day holiday. We will resume normal hours on Tuesday. ',
    //  --- Thanksgiving message ---
    //'appMOTD'                        => '<h3>Thanksgiving Holiday</h3> Due to the 
    //  Thanksgiving Day holiday, the office will be closed.  We apologize for the inconvenience. <br/>
    //  Debido a la celebración del Día de Acción de Gracias, la oficina estará cerrada. 
    //  Nuestras disculpas por cualquier molestia.',  // site Message of the Day
    //  --- Xmas/NewYear message ---
    //'appMOTD'                        => '<h3>Christmas / New Year Holiday Closure</h3> 
    //  Our offices will be closed December 25, and January 1, in observance of the Christmas 
    //  and New Year holidays. We will resume normal hours the next day. Happy Holidays!', 
    //  --- NewYear message ---
    //'appMOTD'                        => '<h3>New Year Holiday Closure</h3> Our offices will be 
    // closed January 1, in observance of the New Year holidays. We will resume normal hours 
    // the next day. Happy Holidays!',  // site Message of the Day
 
    // Test Site
    //'appMOTD'                       => '<h3>TEST SITE</h3> This site is for testing only.', 
 
    // --- MOTD Date Range (comment lines to display permanently) ---
    //'appMOTDStartDate'              => '2017-09-07',  // Start date (YYYY-MM-DD)
    //'appMOTDStopDate'               => '2017-09-11',  // Stop date (YYYY-MM-DD)
];

Main/Web Config

/frontend/config/main-local.php and /backend/config/main-local.php (advanced), or /[app]/config/web.php (basic)

return [
    'components' => [
        'request' => [
            // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation.
            // Must be UNIQUE to project to avoid conflicts.
            // NOTE: In Advanced app, 'Request' can only be used in frontend or backend.  
            //       Do not add to 'common' config.  If added to 'common' config, 
            //       console commands fail with an exception.
            //
            // Preferably, add to local config:
            // $config['components']['request']['cookieValidationKey'] = 'my@s3cr3tk3y_myapp';
            'cookieValidationKey' => 'my secret key goes here (or in web-local.php or main-local.php)_' . $params['appId'],
 
            // Use a custom name per app for csrf cookie to avoid clashes with other Yii apps
            'csrfParam' => 'csrf_' . $params['appId'],
            'csrfCookie' => [
                'httpOnly' => true,
            ],
        ],
        ...
        'urlManager' => [
            'enablePrettyUrl' => true,
            'showScriptName'  => false,
            'rules'           => []
        ],
        //...
        'formatter' => [
           'class'           => 'yii\i18n\Formatter',
           'dateFormat'      => 'php:M d, Y',
           'datetimeFormat'  => 'php:M d, Y H:i:s',
           'timeFormat'      => 'php:H:i:s', 
           'defaultTimeZone' => 'America/New_York'
        ],
 
        // To avoid session conflicts with other Yii2 apps
        'user' => [
            'identityClass'   => 'app\models\User',   // for basic app
            //'identityClass'   => 'common\models\User',   // for advanced app
            'enableAutoLogin' => true,
            'identityCookie'  => [
                'name' => $params['appId'] . '_User', // unique for app
                //'path' => '/backend/web'  // correct path for the app web folder.
            ],
        ],
        'session' => [
            'name'     => $params['appId'] . '_SessionId', // unique for app
            'savePath' => __DIR__ . '/../runtime', // a temporary folder for app
        ],
        'mailer' => [
            'class' => 'yii\swiftmailer\Mailer',
 
            // Directory that contains the view files 
            // for composing mail messages. Defaults to '@app/mail'
            'viewPath' => '@app/mail',       // for basic app
            //'viewPath' => '@common/mail',  // for advanced app
 
            // Send all mail messages to a file by default. 
            // The messages get stored locally under '@app/runtime/mail'
            'useFileTransport' => true,
            //'fileTransportPath' => '@runtime/mail',
 
            // Send all mail messages as real emails.
            // Set 'useFileTransport' to false,
            // and configure a transport for the mailer.
            //'useFileTransport' => false,
            //'transport' => [
            //    'class'      => 'Swift_SmtpTransport',
            //    'host'       => 'smtp.office365.com',
            //    'username'   => 'smtp@acme.com',
            //    'password'   => 'mypassword',
            //    'port'       => '587',
            //    'encryption' => 'tls',
            //],
        ],
    ]
    //...
];

htaccess File

For urlManager component to work correctly using PrettyUrls, you must do this:

1. Configure Apache to run with ''rewrite_module'' turned on.
2. Create ''.htaccess'' file.

Create a .htaccess file in each web folders (/frontend/web and /backend/web) to contain this:

# use mod_rewrite for pretty URL support
RewriteEngine on
 
# HTTPS redirect for pages users input sensitive data (eg. password)
# NOTE: Disable these in localhost or other server without HTTPS.
#RewriteCond %{HTTPS} off
#RewriteCond %{REQUEST_URI} /(login) [NC]
#RewriteRule ^(.*)$ https://%{SERVER_NAME}%{REQUEST_URI} [R,L]
 
# If a directory or a file exists, use the request directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
 
# Otherwise forward the request to index.php
RewriteRule . index.php

System Variables

Setup application name in [app]/vendor/yiisoft/yii2/base/Application.php:

/**
 * @var string the application name.
 */
public $name = 'My Application';

Debugging

Yii2-debug module needs permission to trace and log in case application is installed on a server other than localhost. Edit file [app]/vendor/yiisoft/yii2-debug/Module.php:

class Module extends \yii\base\Module implements BootstrapInterface
{
    /**
     * @var array the list of IPs that are allowed to access this module.
     * Each array element represents a single IP filter which can be either an IP address
     * or an address with wildcard (e.g. 192.168.0.*) to represent a network segment.
     * The default value is `['127.0.0.1', '::1']`, which means the module can only be accessed
     * by localhost.
     */
    public $allowedIPs = ['127.0.0.1', '::1', '192.168.0.*'];
    ...
}    

Even better, just add the settings to your configuration in @app/config/web.php:

if (YII_ENV_DEV) {
    $config['modules']['debug'] = [
        'class' => 'yii\debug\Module',
        'allowedIPs' => ['127.0.0.1', '::1', '192.168.0.*'],
    ];
}    
User Authentication / RBAC
  • For the basic application template, users are added to text file in [app]/models/User.php.
  • For the advanced application template, users and permissions have to be added following this procedure:
    • [app]$ init (if not done so yet to generate the local config files).
    • Edit user table definition in migration script in [app]/console/migrations/m130524_201442_init.php
    • [app]$ yii migrate
    • Add RBAC support using: Role Based Access Control (RBAC)
Basic Template

Main template: Edit /app/views/layouts/main.php:

<head>
  ...
  <link rel="shortcut icon" href="<?= Yii::$app->homeUrl; ?>favicon.ico" type="image/x-icon" />
</head>
...
  <?php
      NavBar::begin([
       'brandLabel' => 'Acme Inc.',
       // if 'companyName' param declared in config/params.php
       //'brandLabel' => Yii::$app->params['companyName'],
       //
       // if 'appName' param declared in config/params.php
       //'brandLabel' => Yii::$app->params['appName'],  
 
       // Edit menu as needed
       ...
  ?>
 
  <!-- Edit footer as needed -->
  <footer class="footer">
        <div class="container">
            <p class="pull-left">&copy; Acme Inc. <?= date('Y') ?></p>
            <!-- if 'companyName' param declared in config/params.php -->
            <p class="pull-left">&copy; <?= Yii::$app->params['companyName'] ?> <?= date('Y') ?></p>  
            <p class="pull-right"><?= Yii::powered() ?></p>
        </div>
  </footer>
>

Frontpage: Edit /app/views/site/index.php:

...
//$this->title = 'Acme Application';
$this->title = Yii::$app->params['companyName'];
...
// Edit view as needed
...
Custom Theme

Add theme settings to main configuration. Eg: basic:

...
return [
    'components' => [
        ...
        'view' => [
            'theme' => [
                'basePath' => '@app/themes/basic',    // dir containing themed resources (CSS, JS, images, etc.)
                //'baseUrl' => '@web/themes/basic',   // URL for theme if in [app]/web/themes
                'baseUrl'  => '@web/../themes/basic', // URL for theme if in [app]/themes
                'pathMap' => [
                    '@app/views' => [  // replacement rules of view files
                        '@app/themes/christmas',
                        '@app/themes/basic',
                    ],
                    '@app/modules' => '@app/themes/basic/modules', 
                    '@app/widgets' => '@app/themes/basic/widgets',
            ],
        ],
        // Alternatively, use the following:
        //'layout' => 'mytheme',   // `@web/../themes/mytheme/views/` contain mytheme.php in this case
    ],
];

Copy [app]/views/layouts and [app]/views/site (and any other folders in views that you want to override), and place them in @app/themes/basic/views. Copy any required resource folders from [app]/web such as [app]/web/css and [app]/web/js into @app/themes/basic/files.

Edit main layout file [app]/views/layouts/main.phpto include the correct CSS files and theme resources:

...
<head>
    ...
    <title><?= Html::encode($this->title) ?></title>
    <?php $this->head() ?>
    <!-- ### Custom CSS files ### !-->
    <link rel='stylesheet' href='<?php echo $this->theme->baseUrl; ?>/files/css/bootstrap.min.css'/>
    <link rel='stylesheet' href='<?php echo $this->theme->baseUrl; ?>/files/css/custom.min.css'/>
</head>
...

Theme Inheritance

Sometimes you may want to define a basic theme which contains a basic look and feel of the application, and then based on the current holiday, you may want to vary the look and feel slightly. You can achieve this goal using theme inheritance which is done by mapping a single view path to multiple targets. For example,

'pathMap' => [
    '@app/views' => [
        '@app/themes/christmas',
        '@app/themes/basic',
    ],
]

In this case, the view @app/views/site/index.php would be themed as either @app/themes/christmas/site/index.php or @app/themes/basic/site/index.php, depending on which themed file exists. If both themed files exist, the first one will take precedence. In practice, you would keep most themed view files in @app/themes/basic and customize some of them in @app/themes/christmas.

Read more: Yii 2 Output Theming

Gii Configuration

Assuming that [app] can be basic, frontend, backend or common, edit /[app]/config/web.php (Basic) or edit /[app]/config/main.php (Advanced) (See more: Guide Tool: Gii):

return [
    ...
    'bootstrap' => ['log','gii'],
    'modules' => [
        'gii' => [
            'class' => 'yii\gii\Module',
            'allowedIPs' => ['127.0.0.1', '::1', '192.168.0.*', '192.168.178.20'] // adjust this to your needs
        ],
    ],
    ...
];

Alternatively,

if (YII_ENV_DEV) {
    // configuration adjustments for 'dev' environment
    $config['bootstrap'][] = 'debug';
    $config['modules']['debug'] = [
        'class' => 'yii\debug\Module',
    ];
 
    $config['bootstrap'][] = 'gii';
    $config['modules']['gii'] = [
        'class' => 'yii\gii\Module',
        'allowedIPs' => ['127.0.0.1', '::1', '192.168.0.*'] // adjust this to your needs
    ];
}

Run Gii

Create Database

Run Gii using:

Generate Models, Controllers and CRUD:

  • Model Class: Enter fully qualified class name of new or already created Model.
    • Basic: app\models\Products
    • Advanced: frontend\models\Products.
    • Note: If your model was generated in the backend, put backend instead of frontend. Eg: backend\models\Products
  • Search Model Class: Provide search model class. Basic: app\models\ProductsSearch, or Advanced: frontend\models\ProductsSearch
  • Controller Class: Provide controller class to be generated. Basic: app\controllers\ProductsController, or Advanced: frontend\controllers\ProductsController

Access controller:

1. Possible error: Class ''frontend\models\Products'' does not exist or has syntax error.
2. Solution: In model and controller, replace ''namespace app\models'' to ''namespace frontend\models'' or ''namespace backend\models''
Shared Hosting

To set up as a shared hosting for both the front and backend using the advanced site:

  • Move frontend/web content to the public www or public_html folder in your shared host.
  • Move backend/web content to an admin folder inside the public www or public_html folder in your shared host, such as www/admin.
  • For each folder, adjust the paths accordingly in index.php and index-test.php.

Edit file backend/config/main.php as follows:

'components' => [
    'request' => [
        // Use a custom name per app for csrf cookie to avoid clashes with other Yii apps
        'csrfParam' => '_csrf-backend_' . $params['appId'],
        'csrfCookie' => [
            'httpOnly' => true,
            'path' => '/admin',
        ],
    ],
    'user' => [
        'identityClass' => 'common\models\User',
        'enableAutoLogin' => true,
        'identityCookie' => [
            'name' => '_identity-backend',
            'path' => '/admin',
            'httpOnly' => true,
        ],
    ],
    'session' => [
        // this is the name of the session cookie used for login on the backend
        'name' => 'advanced-backend',
        'cookieParams' => [
            'path' => '/admin',
        ],
    ],
],

Test the setup:

Reference:

Custom Domains

To set up custom domains for both the front and backend using the advanced site, edit the following files:

# /etc/hosts
127.0.0.1 example.com
127.0.0.1 admin.example.com

Using a virtual hosts:

# /etc/apache2/sites-available/example.conf
<VirtualHost example.com:80>
    ServerAdmin webmaster@example.com
    ServerName example.com
    DocumentRoot "C:/wamp/www/yii/advanced/frontend/web"
    <Directory "C:/wamp/www/yii/advanced/frontend/web">
        Require all granted
    </Directory>
    Alias /frontend "C:/wamp/www/yii/advanced/frontend/web"
    <Directory "C:/wamp/www/yii/advanced/frontend/web">
        Require all granted
    </Directory>
</VirtualHost>
# /etc/apache2/sites-available/admin.example.conf
<VirtualHost admin.example.com:80>
    ServerAdmin webmaster@example.com
    ServerName admin.example.com
    DocumentRoot "C:/wamp/www/yii/advanced/backend/web"
    <Directory "C:/wamp/www/yii/advanced/backend/web">
        Require all granted
    </Directory>
    Alias /backend "C:/wamp/www/yii/advanced/backend/web"
    <Directory "C:/wamp/www/yii/advanced/backend/web">
        Require all granted
    </Directory>
</VirtualHost>

Alternatively, simply using aliases:

# /etc/apache2/conf.d/example.conf
Alias /frontend "C:/wamp/www/yii/advanced/frontend/web"
<Directory "C:/wamp/www/yii/advanced/frontend/web">
    Require all granted
</Directory>
# /etc/apache2/conf.d/admin.example.conf
Alias /backend "C:/wamp/www/yii/advanced/backend/web"
<Directory "C:/wamp/www/yii/advanced/backend/web">
    Require all granted
</Directory>

Restart apache and visit:

Rewrite Base URL (/basic/web or /frontend/web)

Basic App

Create .htaccess file in [yiiroot] folder:

Options -Indexes
 
<IfModule mod_rewrite.c> 
  Options +FollowSymLinks
  IndexIgnore */*
  RewriteEngine on
 
  # prevents all requests that are not directed at the 
  # public directory to be routed to /web/.
  # if request does not start with web, add it.
  RewriteCond %{REQUEST_URI} !^public
  RewriteRule ^(.*)$ web/$1 [L] 
 
  # if file or directory does not exists, go to /web/index.php 
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  #RewriteRule . /web/index.php 
  RewriteRule . index.php 
</IfModule>
 
# Deny accessing below extensions
<Files ~ "(.json|.lock|.git)">
Order allow,deny
Deny from all
</Files>
 
# Deny accessing dot files
RewriteRule (^\.|/\.) - [F]

Create .htaccess file in [yiiroot]/web/ folder:

RewriteEngine on
 
# Is the request for a non-existent file?
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d 
 
RewriteRule . index.php

Hide the web folder. Edit [yiiroot]/config/web.php file to include the following:

<?php
...
 
use \yii\web\Request;
 
// Set current location to be root directory, i.e. '/web' becomes '/'
// Mod_Rewrite procedure will send traffic to '/' if files are in '/var/www/html'
$baseUrl = str_replace('/web', '', (new \yii\web\Request)->getBaseUrl());
 
return [
    //...
 
    'components' => [
        'request' => [
            // Define request. Must have a baseUrl specified.
            // Required if wanting to hide 'web' folder from url.
            'baseUrl' => $baseUrl,
 
            //...
        ],
        // Activate urlManager. Must have baseUrl specified.
        'urlManager' => [
            'baseUrl'         => $baseUrl,
            'enablePrettyUrl' => true,
            'showScriptName'  => false,
            'rules' => []
        ],
 
        //...
    ],
    'params' => $params,
];

Advanced App

Rewrite Frontend URLs to be simpler. We do not care about the Backend URLs because those are not for public consumption.

Create .htaccess file in [yiiroot] folder:

Options -Indexes
 
<IfModule mod_rewrite.c> 
  RewriteEngine on
 
  # prevents all requests that are not directed at the 
  # public directory to be routed to /frontend/web/.
  # if request does not start with web, add it.
  RewriteCond %{REQUEST_URI} !^public
  RewriteRule ^(.*)$ frontend/web/$1 [L] 
</IfModule>
 
# Deny accessing below extensions
<Files ~ "(.json|.lock|.git)">
Order allow,deny
Deny from all
</Files>
 
# Deny accessing dot files
RewriteRule (^\.|/\.) - [F]

Alternatively, for Advanced Applications:

Options +FollowSymLinks
IndexIgnore */*
RewriteEngine on
 
# if request begins with /admin, remove admin and add /backend/web/
RewriteCond %{REQUEST_URI} ^/admin
RewriteRule ^admin\/?(.*) /backend/web/$1
 
# other requests add /frontend/web/$1
RewriteCond %{REQUEST_URI} !^/(frontend/web|backend/web|admin)
RewriteRule (.*) /frontend/web/$1
 
# if frontend request 
RewriteCond %{REQUEST_URI} ^/frontend/web
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /frontend/web/index.php 
 
# if backend request
RewriteCond %{REQUEST_URI} ^/backend/web
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /backend/web/index.php 

Create .htaccess file in [yiiroot]/frontend/web/ folder:

RewriteEngine on
 
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d 
 
RewriteRule . index.php

Edit [yiiroot]/frontend/config/main.php file to include the following:

<?php
...
 
use \yii\web\Request;
 
// Alternative 1 (for any URL)
// Use current location as root, i.e. '/frontend/web' becomes '/'
// The Rewrite procedure to send traffic to '/' if files are in '/var/www/html'
$baseUrl = str_replace('/frontend/web', '', (new \yii\web\Request)->getBaseUrl());
 
// Alternative 2 (optional for specific URLs)
// The Rewrite procedure to send traffic to '/blog' if files are in '/var/www/html/blog'
//$baseUrl = str_replace('/blog/frontend/web', '/blog/', (new \yii\web\Request)->getBaseUrl());
 
return [
    'id' => 'app-frontend',
    ...
 
    'components' => [
 
        // Define request. Must have a baseUrl specified
        'request' => [
            'baseUrl'   => $baseUrl,
            //'baseUrl' => '/',       // or manually set it to '/'
            //'baseUrl' => '/blog',   // or manually set it to '/blog'
        ],
        // Define urlManager. Must have a baseUrl specified
        'urlManager' => [
            'baseUrl'         => $baseUrl,
            //'baseUrl'       => '/',       // or manually set it to '/'
            //'baseUrl'       => '/blog',   // or manually set it to '/blog'
            'enablePrettyUrl' => true,
            'showScriptName'  => false,
            'rules' => []
        ],
 
        ...
    ],
    'params' => $params,
];

To enable mod_rewrite logging to trace through .htaccess settings, use this in Appache config httpd.conf:

<IfModule mod_rewrite.c> 
  # mod_rewrite 2.2
  # Log to a file:
  #RewriteLog "c:/wamp/logs/rewrite.log"
  #RewriteLogLevel 3
 
  # mod_rewrite 2.4
  LogLevel alert rewrite:trace3
</IfModule>
Configuring Different Sessions for Authentication to Separate Yii Apps

You can configure different identity cookies and sessions for your user component for frontend and backend app or totally different Yii apps. Note the unique name property in identityCookie.

Backend Config

// in backend/config/main.php
$config = [
    ...
    'components' => [
        'user' => [
            'identityClass' => 'app\models\User',
            'enableAutoLogin' => true,
            'identityCookie' => [
                'name' => $params['appId'] . '_backendUser', // unique for backend
                //'path'=>'/backend/web'  // correct path for the backend app.
            ]
        ],
        'session' => [
            'name' => $params['appId'] . '_backendSessionId', // unique for backend
            'savePath' => __DIR__ . '/../runtime', // a temporary folder on backend
        ],
    ]
];

Frontend Config

// in frontend/config/main.php
$config = [
    ...
    'components' => [
        'user' => [
            'identityClass' => 'app\models\User',
            'enableAutoLogin' => true,
            'identityCookie' => [
                'name' => $params['appId'] . '_frontendUser', // unique for frontend
                //'path'=>'/frontend/web'  // correct path for the frontend app.
            ]
        ],
        'session' => [
            'name' => $params['appId'] . '_frontendSessionId', // unique for frontend
            'savePath' => __DIR__ . '/../runtime', // a temporary folder on frontend
        ],
    ]
];

See Also: