If you're asking, "What's Yii?", check out my earlier tutorial: Introduction to the Yii Framework, which reviews the benefits of Yii and includes an overview of what's new in Yii 2.0, released October 12th, 2014.
This is part four of a series on Yii2. In Programming With Yii2: Getting Started, we set up Yii2 locally, built a Hello World application, set up a remote server, and used Github to deploy our code. In part two, we learned about Yii's implementation of its Model View Controller architecture and how to build web pages and forms that collect and validate data. In part three, we learned about working with databases and ActiveRecord. In this tutorial, we'll walk you through integrating a popular user registration plugin.
For these examples, we'll continue building on our hello app available in the Tuts+ repository so that you can follow along.
User Registration for Your Web Application
Almost any web application of any usefulness requires some form of user registration. Yii provides a couple of ways to approach user registration, both relatively straightforward. This is one of the things I like about using Yii over vanilla PHP—in moments, I can have a fully featured web application framework ready to build cool stuff on.
There are few reasons to rebuild the wheel and code user authentication and its many requirements and corollary features from scratch, e.g. sending emails and authentication for registration verification, password recovery, third party social authentication, et al.
The Yii2 Advanced Application Template provides built-in user registration; we're using this approach in my Building Your Startup series. However, in this series, we've been building on Yii2's basic application template. The default basic application template includes hard coded user login, which isn't very useful.
Another approach to user registration is to use third party extensions. For this tutorial, I'll walk you through using Dmitry Erofeev's Yii2-User extension. Documentation for Yii2-User is available here. Erofeev's building other plugins for Yii2 as well.
Installation of Yii2-User
Let's get started installing the Yii2-User extension. We'll follow the installation instructions.
Installing Yii2-User With Composer
First, we need to add Yii2-User to composer's required extensions. Edit the /composer.json file to include Yii2-User:
"require": { "php": ">=5.4.0", "yiisoft/yii2": "*", "yiisoft/yii2-bootstrap": "*", "yiisoft/yii2-swiftmailer": "*", "dektrium/yii2-user": "*" },
Then, when we update composer, you'll see something like this:
Admins-MacBook-Pro-2:hello Jeff$ composer update Loading composer repositories with package information Updating dependencies (including require-dev) - Removing yiisoft/yii2-composer (2.0.0) - Installing yiisoft/yii2-composer (2.0.1) Downloading: 100% ... - Installing dektrium/yii2-user (v0.8.2) Downloading: 100% Writing lock file Generating autoload files
Update the Database
Next, we run the database migration for Yii2-User. This creates the database tables that the extension requires. These will manage user accounts and credentials.
hello Jeff$ php yii migrate/up --migrationPath=@vendor/dektrium/yii2-user/migrations Yii Migration Tool (based on Yii v2.0.1) Total 6 new migrations to be applied: m140209_132017_init m140403_174025_create_account_table m140504_113157_update_tables m140504_130429_create_token_table m140830_171933_fix_ip_field m140830_172703_change_account_table_name Apply the above migrations? (yes|no) [no]:yes *** applying m140209_132017_init > create table {{%user}} ... done (time: 0.010s) > create unique index user_unique_username on {{%user}} (username) ... done (time: 0.015s) > create unique index user_unique_email on {{%user}} (email) ... done (time: 0.012s) > create unique index user_confirmation on {{%user}} (id, confirmation_token) ... done (time: 0.011s) > create unique index user_recovery on {{%user}} (id, recovery_token) ... done (time: 0.010s) > create table {{%profile}} ... done (time: 0.007s) > add foreign key fk_user_profile: {{%profile}} (user_id) references {{%user}} (id) ... done (time: 0.010s) *** applied m140209_132017_init (time: 0.078s) *** applying m140403_174025_create_account_table > create table {{%account}} ... done (time: 0.008s) > create unique index account_unique on {{%account}} (provider,client_id) ... done (time: 0.010s) > add foreign key fk_user_account: {{%account}} (user_id) references {{%user}} (id) ... done (time: 0.009s) *** applied m140403_174025_create_account_table (time: 0.027s) *** applying m140504_113157_update_tables > drop index user_confirmation ... done (time: 0.007s) > drop index user_recovery ... done (time: 0.008s) > drop column confirmation_token from table {{%user}} ... done (time: 0.009s) > drop column confirmation_sent_at from table {{%user}} ... done (time: 0.009s) > drop column recovery_token from table {{%user}} ... done (time: 0.007s) > drop column recovery_sent_at from table {{%user}} ... done (time: 0.008s) > drop column logged_in_from from table {{%user}} ... done (time: 0.007s) > drop column logged_in_at from table {{%user}} ... done (time: 0.008s) > rename column registered_from in table {{%user}} to registration_ip ... done (time: 0.009s) > add column flags integer NOT NULL DEFAULT 0 to table {{%user}} ... done (time: 0.010s) > rename column properties in table {{%account}} to data ... done (time: 0.008s) *** applied m140504_113157_update_tables (time: 0.090s) *** applying m140504_130429_create_token_table > create table {{%token}} ... done (time: 0.006s) > create unique index token_unique on {{%token}} (user_id,code,type) ... done (time: 0.010s) > add foreign key fk_user_token: {{%token}} (user_id) references {{%user}} (id) ... done (time: 0.009s) *** applied m140504_130429_create_token_table (time: 0.026s) *** applying m140830_171933_fix_ip_field > alter column registration_ip in table {{%user}} to bigint ... done (time: 0.010s) *** applied m140830_171933_fix_ip_field (time: 0.011s) *** applying m140830_172703_change_account_table_name > rename table {{%account}} to {{%social_account}} ... done (time: 0.001s) *** applied m140830_172703_change_account_table_name (time: 0.002s) Migrated up successfully.
Update the Configuration File
Next, we need to tell Yii to use the Yii2-User component. In /config/web.php, we replace the default User component...
'user' => [ 'identityClass' => 'app\models\User', 'enableAutoLogin' => true, ],
... with the Yii2-User component:
'user' => [ 'class' => 'dektrium\user\Module', 'enableUnconfirmedLogin' => true, 'confirmWithin' => 21600, 'cost' => 12, 'admins' => ['admin'] ],
Activate the SwiftMailer
Since Yii2-User uses email to send out registration confirmations and forgotten passwords, it's time to activate our SwiftMailer configuration. In config/web.php, replace the default Mailer configuration here...
'mailer' => [ 'class' => 'yii\swiftmailer\Mailer', // 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, ],
... with this—you'll need to include your own SMTP credentials:
'mailer' => [ 'class' => 'yii\swiftmailer\Mailer', 'viewPath' => '@app/mailer', 'useFileTransport' => false, 'transport' => [ 'class' => 'Swift_SmtpTransport', 'host' => 'your-host-domain e.g. smtp.gmail.com', 'username' => 'your-email-or-username', 'password' => 'your-password', 'port' => '587', 'encryption' => 'tls', ], ],
Integration of Yii2-User
Now, we need to link our navigation bar to the Yii2-User controller paths. In /views/layouts/main.php, we update the navigation bar array definition for the Bootstrap menu. Replace the current navigation bar...
echo Nav::widget([ 'options' => ['class' => 'navbar-nav navbar-right'], 'items' => [ ['label' => 'Home', 'url' => ['/site/index']], ['label' => 'Status', 'url' => ['/status/index']], ['label' => 'About', 'url' => ['/site/about']], ['label' => 'Contact', 'url' => ['/site/contact']], Yii::$app->user->isGuest ? ['label' => 'Login', 'url' => ['/site/login']] : ['label' => 'Logout (' . Yii::$app->user->identity->username . ')', 'url' => ['/site/logout'], 'linkOptions' => ['data-method' => 'post']], ], ]);
... with the following array definition:
$navItems=[ ['label' => 'Home', 'url' => ['/site/index']], ['label' => 'Status', 'url' => ['/status/index']], ['label' => 'About', 'url' => ['/site/about']], ['label' => 'Contact', 'url' => ['/site/contact']] ]; if (Yii::$app->user->isGuest) { array_push($navItems,['label' => 'Sign In', 'url' => ['/user/login']],['label' => 'Sign Up', 'url' => ['/user/register']]); } else { array_push($navItems,['label' => 'Logout (' . Yii::$app->user->identity->username . ')', 'url' => ['/site/logout'], 'linkOptions' => ['data-method' => 'post']] ); } echo Nav::widget([ 'options' => ['class' => 'navbar-nav navbar-right'], 'items' => $navItems, ]);
Reload the application and click the Sign Up link in the navigation bar. You should see something like this:
When you click Sign Up, you'll see the confirmation notification. This tells us an email has been sent that we need to click on to verify our registration.
You'll receive an email much like this one:
Click on the link in the email and you'll see something like this:
Notice the login state maintained by Yii2 and the Yii2-User component—it's displayed in the navigation bar above. Click Logout and let's walk through the Sign In page:
Yii2-User also includes password recovery:
Just like that, we have a hugely important core authentication component for our application.
Yii2-User also has a number of configuration features which you can explore further on your own, e.g. third party social authentication. We'll likely return to them in a later tutorial.
What's Next?
I hope you've found this useful for your own Yii2 web application. If you'd like to know when the next Yii2 tutorial arrives, follow me @reifman on Twitter or check my instructor page. My instructor page will include all the articles from this series as soon as they are published.
Comments