diff --git a/assets/AppAsset.php b/assets/AppAsset.php
index f0ab4dd8b..56e81dac0 100644
--- a/assets/AppAsset.php
+++ b/assets/AppAsset.php
@@ -6,9 +6,14 @@
* @license https://www.yiiframework.com/license/
*/
+declare(strict_types=1);
+
namespace app\assets;
+use yii\bootstrap5\BootstrapAsset;
use yii\web\AssetBundle;
+use yii\web\View;
+use yii\web\YiiAsset;
/**
* Main application asset bundle.
@@ -27,10 +32,10 @@ class AppAsset extends AssetBundle
'js/color-mode.js',
];
public $jsOptions = [
- 'position' => \yii\web\View::POS_HEAD,
+ 'position' => View::POS_HEAD,
];
public $depends = [
- 'yii\web\YiiAsset',
- 'yii\bootstrap5\BootstrapAsset'
+ YiiAsset::class,
+ BootstrapAsset::class,
];
}
diff --git a/commands/HelloController.php b/commands/HelloController.php
index 28dba79cd..7da32fb0d 100644
--- a/commands/HelloController.php
+++ b/commands/HelloController.php
@@ -6,6 +6,8 @@
* @license https://www.yiiframework.com/license/
*/
+declare(strict_types=1);
+
namespace app\commands;
use yii\console\Controller;
@@ -26,9 +28,9 @@ class HelloController extends Controller
* @param string $message the message to be echoed.
* @return int Exit code
*/
- public function actionIndex($message = 'hello world')
+ public function actionIndex(string $message = 'hello world'): int
{
- echo $message . "\n";
+ echo "{$message}\n";
return ExitCode::OK;
}
diff --git a/config/console.php b/config/console.php
index ca429affa..4f8283823 100644
--- a/config/console.php
+++ b/config/console.php
@@ -15,12 +15,12 @@
],
'components' => [
'cache' => [
- 'class' => 'yii\caching\FileCache',
+ 'class' => \yii\caching\FileCache::class,
],
'log' => [
'targets' => [
[
- 'class' => 'yii\log\FileTarget',
+ 'class' => \yii\log\FileTarget::class,
'levels' => ['error', 'warning'],
],
],
@@ -41,13 +41,13 @@
// configuration adjustments for 'dev' environment
$config['bootstrap'][] = 'gii';
$config['modules']['gii'] = [
- 'class' => 'yii\gii\Module',
+ 'class' => \yii\gii\Module::class,
];
// configuration adjustments for 'dev' environment
// requires version `2.1.21` of yii2-debug module
$config['bootstrap'][] = 'debug';
$config['modules']['debug'] = [
- 'class' => 'yii\debug\Module',
+ 'class' => \yii\debug\Module::class,
// uncomment the following to add your IP if you are not connecting from localhost.
//'allowedIPs' => ['127.0.0.1', '::1'],
];
diff --git a/config/db.php b/config/db.php
index bc75e616f..d83cbf1c9 100644
--- a/config/db.php
+++ b/config/db.php
@@ -1,7 +1,7 @@
'yii\db\Connection',
+ 'class' => \yii\db\Connection::class,
'dsn' => 'mysql:host=localhost;dbname=yii2basic',
'username' => 'root',
'password' => '',
diff --git a/config/test.php b/config/test.php
index fb5e2929e..6320bcdf0 100644
--- a/config/test.php
+++ b/config/test.php
@@ -9,6 +9,9 @@
return [
'id' => 'basic-tests',
'basePath' => dirname(__DIR__),
+ 'bootstrap' => [
+ \app\tests\Support\MailerBootstrap::class,
+ ],
'aliases' => [
'@bower' => '@vendor/bower-asset',
'@npm' => '@vendor/npm-asset',
@@ -18,10 +21,9 @@
'db' => $db,
'mailer' => [
'class' => \yii\symfonymailer\Mailer::class,
- 'viewPath' => '@app/mail',
- // send all mails to a file by default.
+ 'messageClass' => \yii\symfonymailer\Message::class,
'useFileTransport' => true,
- 'messageClass' => 'yii\symfonymailer\Message'
+ 'viewPath' => '@app/mail',
],
'assetManager' => [
'basePath' => __DIR__ . '/../web/assets',
@@ -30,7 +32,7 @@
'showScriptName' => true,
],
'user' => [
- 'identityClass' => 'app\models\User',
+ 'identityClass' => \app\models\User::class,
],
'request' => [
'cookieValidationKey' => 'test',
diff --git a/config/web.php b/config/web.php
index 8b9dd3f94..8c43a34e2 100644
--- a/config/web.php
+++ b/config/web.php
@@ -7,6 +7,16 @@
'id' => 'basic',
'basePath' => dirname(__DIR__),
'bootstrap' => ['log'],
+ 'container' => [
+ 'singletons' => [
+ \yii\mail\MailerInterface::class => [
+ 'class' => \yii\symfonymailer\Mailer::class,
+ // send all mails to a file by default.
+ 'useFileTransport' => true,
+ 'viewPath' => '@app/mail',
+ ],
+ ],
+ ],
'aliases' => [
'@bower' => '@vendor/bower-asset',
'@npm' => '@vendor/npm-asset',
@@ -17,26 +27,21 @@
'cookieValidationKey' => '',
],
'cache' => [
- 'class' => 'yii\caching\FileCache',
+ 'class' => \yii\caching\FileCache::class,
],
'user' => [
- 'identityClass' => 'app\models\User',
+ 'identityClass' => \app\models\User::class,
'enableAutoLogin' => true,
],
'errorHandler' => [
'errorAction' => 'site/error',
],
- 'mailer' => [
- 'class' => \yii\symfonymailer\Mailer::class,
- 'viewPath' => '@app/mail',
- // send all mails to a file by default.
- 'useFileTransport' => true,
- ],
+ 'mailer' => \yii\mail\MailerInterface::class,
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
- 'class' => 'yii\log\FileTarget',
+ 'class' => \yii\log\FileTarget::class,
'levels' => ['error', 'warning'],
],
],
@@ -58,14 +63,14 @@
// configuration adjustments for 'dev' environment
$config['bootstrap'][] = 'debug';
$config['modules']['debug'] = [
- 'class' => 'yii\debug\Module',
+ 'class' => \yii\debug\Module::class,
// uncomment the following to add your IP if you are not connecting from localhost.
//'allowedIPs' => ['127.0.0.1', '::1'],
];
$config['bootstrap'][] = 'gii';
$config['modules']['gii'] = [
- 'class' => 'yii\gii\Module',
+ 'class' => \yii\gii\Module::class,
// uncomment the following to add your IP if you are not connecting from localhost.
//'allowedIPs' => ['127.0.0.1', '::1'],
];
diff --git a/controllers/SiteController.php b/controllers/SiteController.php
index a60bffafb..93a7da2f7 100644
--- a/controllers/SiteController.php
+++ b/controllers/SiteController.php
@@ -1,21 +1,37 @@
[
@@ -41,14 +57,14 @@ public function behaviors()
/**
* {@inheritdoc}
*/
- public function actions()
+ public function actions(): array
{
return [
'error' => [
- 'class' => 'yii\web\ErrorAction',
+ 'class' => ErrorAction::class,
],
'captcha' => [
- 'class' => 'yii\captcha\CaptchaAction',
+ 'class' => CaptchaAction::class,
'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
'transparent' => true,
],
@@ -60,7 +76,7 @@ public function actions()
*
* @return string
*/
- public function actionIndex()
+ public function actionIndex(): string
{
return $this->render('index');
}
@@ -70,21 +86,21 @@ public function actionIndex()
*
* @return Response|string
*/
- public function actionLogin()
+ public function actionLogin(): Response|string
{
if (!Yii::$app->user->isGuest) {
return $this->goHome();
}
- $model = new LoginForm();
- if ($model->load(Yii::$app->request->post()) && $model->login()) {
+ $model = new LoginForm($this->security);
+
+ if ($model->load($this->request->post()) && $model->login()) {
return $this->goBack();
}
$model->password = '';
- return $this->render('login', [
- 'model' => $model,
- ]);
+
+ return $this->render('login', ['model' => $model]);
}
/**
@@ -92,7 +108,7 @@ public function actionLogin()
*
* @return Response
*/
- public function actionLogout()
+ public function actionLogout(): Response
{
Yii::$app->user->logout();
@@ -104,17 +120,24 @@ public function actionLogout()
*
* @return Response|string
*/
- public function actionContact()
+ public function actionContact(): Response|string
{
$model = new ContactForm();
- if ($model->load(Yii::$app->request->post()) && $model->contact(Yii::$app->params['adminEmail'])) {
+
+ $contact = $model->load($this->request->post()) && $model->contact(
+ $this->mailer,
+ Yii::$app->params['adminEmail'],
+ Yii::$app->params['senderEmail'],
+ Yii::$app->params['senderName'],
+ );
+
+ if ($contact) {
Yii::$app->session->setFlash('contactFormSubmitted');
return $this->refresh();
}
- return $this->render('contact', [
- 'model' => $model,
- ]);
+
+ return $this->render('contact', ['model' => $model]);
}
/**
@@ -122,7 +145,7 @@ public function actionContact()
*
* @return string
*/
- public function actionAbout()
+ public function actionAbout(): string
{
return $this->render('about');
}
diff --git a/docs/images/about-dark.png b/docs/images/about-dark.png
index 6da920794..7e3fd1ac3 100644
Binary files a/docs/images/about-dark.png and b/docs/images/about-dark.png differ
diff --git a/docs/images/about-light.png b/docs/images/about-light.png
index 3d7ba7076..da9cf3988 100644
Binary files a/docs/images/about-light.png and b/docs/images/about-light.png differ
diff --git a/docs/images/contact-success-dark.png b/docs/images/contact-success-dark.png
new file mode 100644
index 000000000..b602be278
Binary files /dev/null and b/docs/images/contact-success-dark.png differ
diff --git a/docs/images/contact-success-light.png b/docs/images/contact-success-light.png
new file mode 100644
index 000000000..86c47314b
Binary files /dev/null and b/docs/images/contact-success-light.png differ
diff --git a/docs/images/error-dark.png b/docs/images/error-dark.png
new file mode 100644
index 000000000..406189126
Binary files /dev/null and b/docs/images/error-dark.png differ
diff --git a/docs/images/error-light.png b/docs/images/error-light.png
new file mode 100644
index 000000000..7d47520bd
Binary files /dev/null and b/docs/images/error-light.png differ
diff --git a/models/ContactForm.php b/models/ContactForm.php
index f001d2192..fafdf189b 100644
--- a/models/ContactForm.php
+++ b/models/ContactForm.php
@@ -1,26 +1,27 @@
'Verification Code',
@@ -44,15 +45,20 @@ public function attributeLabels()
/**
* Sends an email to the specified email address using the information collected by this model.
- * @param string $email the target email address
- * @return bool whether the model passes validation
+ *
+ * @param MailerInterface $mailer the mailer component.
+ * @param string $email the target email address.
+ * @param string $senderEmail the sender email address.
+ * @param string $senderName the sender name.
+ *
+ * @return bool whether the model passes validation.
*/
- public function contact($email)
+ public function contact(MailerInterface $mailer, string $email, string $senderEmail, string $senderName): bool
{
if ($this->validate()) {
- Yii::$app->mailer->compose()
+ $mailer->compose()
->setTo($email)
- ->setFrom([Yii::$app->params['senderEmail'] => Yii::$app->params['senderName']])
+ ->setFrom([$senderEmail => $senderName])
->setReplyTo([$this->email => $this->name])
->setSubject($this->subject)
->setTextBody($this->body)
@@ -60,6 +66,7 @@ public function contact($email)
return true;
}
+
return false;
}
}
diff --git a/models/LoginForm.php b/models/LoginForm.php
index 5304eecf4..c39c6ff93 100644
--- a/models/LoginForm.php
+++ b/models/LoginForm.php
@@ -1,29 +1,36 @@
hasErrors()) {
$user = $this->getUser();
- if (!$user || !$user->validatePassword($this->password)) {
+ if (!$user || !$this->security->validatePassword($this->password, $user->passwordHash)) {
$this->addError($attribute, 'Incorrect username or password.');
}
}
@@ -57,11 +64,12 @@ public function validatePassword($attribute, $params)
* Logs in a user using the provided username and password.
* @return bool whether the user is logged in successfully
*/
- public function login()
+ public function login(): bool
{
if ($this->validate()) {
return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600 * 24 * 30 : 0);
}
+
return false;
}
@@ -70,10 +78,11 @@ public function login()
*
* @return User|null
*/
- public function getUser()
+ public function getUser(): User|null
{
- if ($this->_user === false) {
+ if (!$this->_userLoaded) {
$this->_user = User::findByUsername($this->username);
+ $this->_userLoaded = true;
}
return $this->_user;
diff --git a/models/User.php b/models/User.php
index 6343a98b3..304575ae1 100644
--- a/models/User.php
+++ b/models/User.php
@@ -1,37 +1,43 @@
[
'id' => '100',
'username' => 'admin',
- 'password' => 'admin',
+ // password: admin
+ 'passwordHash' => '$2y$13$gYAywKSkhfZDq9FLNdm7buKnvlRxDexf5xipSMAxQPDUxpaptmZJu',
'authKey' => 'test100key',
'accessToken' => '100-token',
],
'101' => [
'id' => '101',
'username' => 'demo',
- 'password' => 'demo',
+ // password: demo
+ 'passwordHash' => '$2y$13$alRLq1PGVMlGYwS/Y3iy3ewQns1Z8ol8Iq6Zb5k7ZwEhblA1aL29y',
'authKey' => 'test101key',
'accessToken' => '101-token',
],
];
-
/**
* {@inheritdoc}
*/
- public static function findIdentity($id)
+ public static function findIdentity($id): static|null
{
return isset(self::$_users[$id]) ? new static(self::$_users[$id]) : null;
}
@@ -39,7 +45,7 @@ public static function findIdentity($id)
/**
* {@inheritdoc}
*/
- public static function findIdentityByAccessToken($token, $type = null)
+ public static function findIdentityByAccessToken($token, $type = null): static|null
{
foreach (self::$_users as $user) {
if ($user['accessToken'] === $token) {
@@ -56,7 +62,7 @@ public static function findIdentityByAccessToken($token, $type = null)
* @param string $username
* @return static|null
*/
- public static function findByUsername($username)
+ public static function findByUsername(string $username): static|null
{
foreach (self::$_users as $user) {
if (strcasecmp($user['username'], $username) === 0) {
@@ -70,7 +76,7 @@ public static function findByUsername($username)
/**
* {@inheritdoc}
*/
- public function getId()
+ public function getId(): int|string
{
return $this->id;
}
@@ -78,7 +84,7 @@ public function getId()
/**
* {@inheritdoc}
*/
- public function getAuthKey()
+ public function getAuthKey(): string|null
{
return $this->authKey;
}
@@ -86,19 +92,8 @@ public function getAuthKey()
/**
* {@inheritdoc}
*/
- public function validateAuthKey($authKey)
+ public function validateAuthKey($authKey): bool
{
return $this->authKey === $authKey;
}
-
- /**
- * Validates password
- *
- * @param string $password password to validate
- * @return bool if password provided is valid for current user
- */
- public function validatePassword($password)
- {
- return $this->password === $password;
- }
}
diff --git a/tests/Support/MailerBootstrap.php b/tests/Support/MailerBootstrap.php
new file mode 100644
index 000000000..898c1aa53
--- /dev/null
+++ b/tests/Support/MailerBootstrap.php
@@ -0,0 +1,28 @@
+setSingleton(MailerInterface::class, $app->mailer);
+ }
+}
diff --git a/tests/Unit/LoginTest.php b/tests/Unit/LoginTest.php
index efc19afc4..05e52aa62 100644
--- a/tests/Unit/LoginTest.php
+++ b/tests/Unit/LoginTest.php
@@ -7,18 +7,19 @@
use app\controllers\SiteController;
use app\models\User;
use Yii;
-use yii\console\Application;
+use yii\base\Security;
use yii\web\View;
-use function dirname;
-
final class LoginTest extends \Codeception\Test\Unit
{
public function testRenderLoginWrongUsername(): void
{
- $controller = new SiteController('site', Yii::$app);
-
- Yii::$app->controller = $controller;
+ $controller = new SiteController(
+ 'site',
+ Yii::$app,
+ Yii::$app->mailer,
+ new Security(),
+ );
$view = new View(['context' => $controller]);
@@ -27,9 +28,9 @@ public function testRenderLoginWrongUsername(): void
$controller->actionLogin();
self::assertStringNotContainsString(
- '',
+ 'Logout (admin)',
$view->render('//layouts/main.php', ['content' => 'Hello World°']),
- 'Failed asserting that the logout link is rendered for a logged-in user.',
+ 'Failed asserting that the logout link is not rendered for a wrong username.',
);
}
}
diff --git a/tests/Unit/LogoutTest.php b/tests/Unit/LogoutTest.php
index aa62c17d0..f6e38af2c 100644
--- a/tests/Unit/LogoutTest.php
+++ b/tests/Unit/LogoutTest.php
@@ -7,6 +7,7 @@
use app\controllers\SiteController;
use app\models\User;
use Yii;
+use yii\base\Security;
use yii\web\IdentityInterface;
use yii\web\View;
@@ -16,9 +17,12 @@ public function testRenderLogoutLinkWhenUserIsLoggedIn(): void
{
$user = User::findIdentity('100');
- $controller = new SiteController('site', Yii::$app);
-
- Yii::$app->controller = $controller;
+ $controller = new SiteController(
+ 'site',
+ Yii::$app,
+ Yii::$app->mailer,
+ new Security(),
+ );
$view = new View(['context' => $controller]);
@@ -34,18 +38,27 @@ public function testRenderLogoutLinkWhenUserIsLoggedIn(): void
Yii::$app->user->login($user);
+ $html = $view->render('//layouts/main.php', ['content' => 'Hello World°']);
+
self::assertStringContainsString(
- '',
- $view->render('//layouts/main.php', ['content' => 'Hello World°']),
+ 'Logout (admin)',
+ $html,
'Failed asserting that the logout link is rendered for a logged-in user.',
);
+ self::assertStringContainsString(
+ 'data-method="post"',
+ $html,
+ 'Failed asserting that the logout link uses POST method.',
+ );
$controller->actionLogout();
+ $html = $view->render('//layouts/main.php', ['content' => 'Hello World°']);
+
self::assertStringNotContainsString(
- '',
- $view->render('//layouts/main.php', ['content' => 'Hello World°']),
- 'Failed asserting that the logout link is rendered for a logged-in user.',
+ 'Logout (admin)',
+ $html,
+ 'Failed asserting that the logout link is not rendered after logout.',
);
}
}
diff --git a/tests/Unit/Models/ContactFormTest.php b/tests/Unit/Models/ContactFormTest.php
index 98bf8f7e7..405e48750 100644
--- a/tests/Unit/Models/ContactFormTest.php
+++ b/tests/Unit/Models/ContactFormTest.php
@@ -5,6 +5,7 @@
namespace app\tests\Unit\Models;
use app\models\ContactForm;
+use Yii;
use yii\mail\MessageInterface;
final class ContactFormTest extends \Codeception\Test\Unit
@@ -23,7 +24,7 @@ public function testEmailIsSentOnContact()
'verifyCode' => 'testme',
];
- verify($model->contact('admin@example.com'))->notEmpty();
+ verify($model->contact(Yii::$app->mailer, 'admin@example.com', 'noreply@example.com', 'Example.com mailer'))->notEmpty();
// using Yii2 module actions to check email was sent
$this->tester->seeEmailIsSent();
diff --git a/tests/Unit/Models/LoginFormTest.php b/tests/Unit/Models/LoginFormTest.php
index acff2f1a4..3aea667ce 100644
--- a/tests/Unit/Models/LoginFormTest.php
+++ b/tests/Unit/Models/LoginFormTest.php
@@ -6,6 +6,7 @@
use app\models\LoginForm;
use Yii;
+use yii\base\Security;
final class LoginFormTest extends \Codeception\Test\Unit
{
@@ -19,6 +20,7 @@ protected function _after()
public function testLoginNoUser()
{
$this->_model = new LoginForm(
+ new Security(),
[
'username' => 'not_existing_username',
'password' => 'not_existing_password',
@@ -32,6 +34,7 @@ public function testLoginNoUser()
public function testLoginWrongPassword()
{
$this->_model = new LoginForm(
+ new Security(),
[
'username' => 'demo',
'password' => 'wrong_password',
@@ -46,6 +49,7 @@ public function testLoginWrongPassword()
public function testLoginCorrect()
{
$this->_model = new LoginForm(
+ new Security(),
[
'username' => 'demo',
'password' => 'demo',
diff --git a/tests/Unit/Models/UserTest.php b/tests/Unit/Models/UserTest.php
index b390675a2..ac2f34950 100644
--- a/tests/Unit/Models/UserTest.php
+++ b/tests/Unit/Models/UserTest.php
@@ -47,7 +47,5 @@ public function testValidateUser()
verify($user->validateAuthKey('test100key'))->notEmpty();
verify($user->validateAuthKey('test102key'))->empty();
- verify($user->validatePassword('admin'))->notEmpty();
- verify($user->validatePassword('123456'))->empty();
}
}
diff --git a/tests/_bootstrap.php b/tests/_bootstrap.php
index 7ceaeaad0..6d9316c43 100644
--- a/tests/_bootstrap.php
+++ b/tests/_bootstrap.php
@@ -1,7 +1,9 @@
+
diff --git a/views/layouts/_head.php b/views/layouts/_head.php
new file mode 100644
index 000000000..c440ca89b
--- /dev/null
+++ b/views/layouts/_head.php
@@ -0,0 +1,40 @@
+registerCsrfMetaTags();
+$this->registerMetaTag(
+ ['charset' => Yii::$app->charset],
+ 'charset',
+);
+$this->registerMetaTag(
+ [
+ 'name' => 'viewport',
+ 'content' => 'width=device-width, initial-scale=1',
+ ],
+);
+$this->registerMetaTag(
+ [
+ 'name' => 'description',
+ 'content' => $this->params['meta_description'] ?? ''
+ ],
+);
+$this->registerMetaTag(
+ [
+ 'name' => 'keywords',
+ 'content' => $this->params['meta_keywords'] ?? ''
+ ],
+);
+$this->registerLinkTag(
+ [
+ 'rel' => 'icon',
+ 'type' => 'image/x-icon',
+ 'href' => Yii::getAlias('@web/favicon.ico'),
+ ],
+);
diff --git a/views/layouts/_header.php b/views/layouts/_header.php
new file mode 100644
index 000000000..e16b2a51a
--- /dev/null
+++ b/views/layouts/_header.php
@@ -0,0 +1,65 @@
+ 'Home',
+ 'url' => ['/site/index'],
+ ],
+ [
+ 'label' => 'About',
+ 'url' => ['/site/about'],
+ ],
+ [
+ 'label' => 'Contact',
+ 'url' => ['/site/contact'],
+ ],
+ [
+ 'label' => 'Login',
+ 'url' => ['/site/login'],
+ 'visible' => Yii::$app->user->isGuest,
+ ],
+ [
+ 'label' => 'Logout (' . Html::encode(Yii::$app->user->identity?->username ?? '') . ')',
+ 'url' => ['/site/logout'],
+ 'linkOptions' => [
+ 'data-method' => 'post',
+ 'class' => 'logout',
+ ],
+ 'visible' => !Yii::$app->user->isGuest,
+ ],
+];
+
+?>
+
- This is the About page. You may modify the following file to customize its content: -
+
+ You may modify the following file to customize its content:
+
+ = __FILE__ ?>
+
+
= __FILE__ ?>
+ = Html::a(
+ 'Go to Homepage',
+ Yii::$app->homeUrl,
+ ['class' => 'btn btn-outline-primary btn-lg'],
+ ) ?>
Thank you for contacting us. We will respond to you as soon as possible. -
- Note that if you turn on the Yii debugger, you should be able
- to view the mail message on the mail panel of the debugger.
- mailer->useFileTransport): ?>
- Because the application is in development mode, the email is not sent but saved as
- a file under = Yii::getAlias(Yii::$app->mailer->fileTransportPath) ?>.
- Please configure the useFileTransport property of the mail
- application component to be false to enable email sending.
-
+ Development mode: email saved under
+ = Yii::getAlias(Yii::$app->mailer->fileTransportPath) ?>
+
+ The above error occurred while the Web server was processing your request. + Please contact us if you think this is a server error. Thank you. +
+ + = Html::a( + 'Go to Homepage', + Yii::$app->homeUrl, + ['class' => 'btn btn-outline-primary btn-lg'], + ) ?>- The above error occurred while the Web server was processing your request. -
-- Please contact us if you think this is a server error. Thank you. -
- - = Html::a('Go to Homepage', Yii::$app->homeUrl, ['class' => 'btn btn-outline-primary']) ?> -You have successfully created your Yii-powered application.
= Yii::t('app', 'Learn Yii step by step: MVC structure, ActiveRecord, migrations, form validation, authentication, RBAC, REST APIs, caching, and testing. Everything you need is covered in one place, from basics to advanced topics.') ?>
+= Yii::t( + 'app', + 'Learn Yii step by step: MVC structure, ActiveRecord, migrations, form validation, authentication, RBAC, REST APIs, caching, and testing. Everything you need is covered in one place, from basics to advanced topics.', + ) ?>
= Yii::t('app', 'The Yii Forum is where thousands of developers share solutions, discuss best practices, and help each other. Before opening a GitHub issue, chances are someone already solved your problem there.') ?>
+= Yii::t( + 'app', + 'The Yii Forum is where thousands of developers share solutions, discuss best practices, and help each other. Before opening a GitHub issue, chances are someone already solved your problem there.', + ) ?>
= Yii::t('app', 'Supercharge your app with battle-tested packages maintained by the core team.') ?>
+= Yii::t( + 'app', + 'Supercharge your app with battle-tested packages maintained by the core team.', + ) ?>