diff --git a/composer.json b/composer.json index f60a8f9..ae6a715 100644 --- a/composer.json +++ b/composer.json @@ -14,10 +14,13 @@ }, "minimum-stability": "stable", "require": { - "php": ">=7.4.0", + "php": ">=8.2.0", "yiisoft/yii2": "~2.0.45", "yiisoft/yii2-bootstrap5": "~2.0.2", - "yiisoft/yii2-symfonymailer": "~2.0.3" + "yiisoft/yii2-symfonymailer": "~2.0.3", + "sam-it/yii2-mariadb": "^3.1", + "bestyii/yii2-gii-rest": "*", + "bestyii/yii2-openapi-reader": "dev-master" }, "require-dev": { "yiisoft/yii2-debug": "~2.1.0", diff --git a/config/db.php b/config/db.php index bc75e61..30f8d86 100644 --- a/config/db.php +++ b/config/db.php @@ -1,11 +1,16 @@ 'yii\db\Connection', - 'dsn' => 'mysql:host=localhost;dbname=yii2basic', + 'class' => Connection::class, + 'dsn' => 'mysql:host=localhost:3307;dbname=yii2basic', 'username' => 'root', - 'password' => '', + 'password' => 'chenx221', 'charset' => 'utf8', + 'schemaMap' => [ + 'mysql' => SamIT\Yii2\MariaDb\Schema::class + ] // Schema cache options (for production environment) //'enableSchemaCache' => true, diff --git a/config/web.php b/config/web.php index 8b9dd3f..ae5b4bc 100644 --- a/config/web.php +++ b/config/web.php @@ -9,12 +9,12 @@ $config = [ 'bootstrap' => ['log'], 'aliases' => [ '@bower' => '@vendor/bower-asset', - '@npm' => '@vendor/npm-asset', + '@npm' => '@vendor/npm-asset', ], 'components' => [ 'request' => [ // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation - 'cookieValidationKey' => '', + 'cookieValidationKey' => '9vuTNyfQqTOWY8fhAajrAhOfX_uaZqZZ', ], 'cache' => [ 'class' => 'yii\caching\FileCache', @@ -67,7 +67,15 @@ if (YII_ENV_DEV) { $config['modules']['gii'] = [ 'class' => 'yii\gii\Module', // uncomment the following to add your IP if you are not connecting from localhost. - //'allowedIPs' => ['127.0.0.1', '::1'], + 'allowedIPs' => ['127.0.0.1', '::1', '192.168.1.*'], + 'generators' => [ //自定义生成器 + 'rest-model' => [ // generator name + 'class' => 'bestyii\giiRest\generators\model\Generator', // generator class + ], + 'rest-crud' => [ // generator name + 'class' => 'bestyii\giiRest\generators\crud\Generator', // generator class + ] + ], ]; } diff --git a/controllers/CountryController.php b/controllers/CountryController.php new file mode 100644 index 0000000..9e8e5bd --- /dev/null +++ b/controllers/CountryController.php @@ -0,0 +1,134 @@ + [ + 'class' => VerbFilter::className(), + 'actions' => [ + 'delete' => ['POST'], + ], + ], + ] + ); + } + + /** + * Lists all Country models. + * + * @return string + */ + public function actionIndex() + { + $searchModel = new CountrySearch(); + $dataProvider = $searchModel->search($this->request->queryParams); + + return $this->render('index', [ + 'searchModel' => $searchModel, + 'dataProvider' => $dataProvider, + ]); + } + + /** + * Displays a single Country model. + * @param string $code Code + * @return string + * @throws NotFoundHttpException if the model cannot be found + */ + public function actionView($code) + { + return $this->render('view', [ + 'model' => $this->findModel($code), + ]); + } + + /** + * Creates a new Country model. + * If creation is successful, the browser will be redirected to the 'view' page. + * @return string|\yii\web\Response + */ + public function actionCreate() + { + $model = new Country(); + + if ($this->request->isPost) { + if ($model->load($this->request->post()) && $model->save()) { + return $this->redirect(['view', 'code' => $model->code]); + } + } else { + $model->loadDefaultValues(); + } + + return $this->render('create', [ + 'model' => $model, + ]); + } + + /** + * Updates an existing Country model. + * If update is successful, the browser will be redirected to the 'view' page. + * @param string $code Code + * @return string|\yii\web\Response + * @throws NotFoundHttpException if the model cannot be found + */ + public function actionUpdate($code) + { + $model = $this->findModel($code); + + if ($this->request->isPost && $model->load($this->request->post()) && $model->save()) { + return $this->redirect(['view', 'code' => $model->code]); + } + + return $this->render('update', [ + 'model' => $model, + ]); + } + + /** + * Deletes an existing Country model. + * If deletion is successful, the browser will be redirected to the 'index' page. + * @param string $code Code + * @return \yii\web\Response + * @throws NotFoundHttpException if the model cannot be found + */ + public function actionDelete($code) + { + $this->findModel($code)->delete(); + + return $this->redirect(['index']); + } + + /** + * Finds the Country model based on its primary key value. + * If the model is not found, a 404 HTTP exception will be thrown. + * @param string $code Code + * @return Country the loaded model + * @throws NotFoundHttpException if the model cannot be found + */ + protected function findModel($code) + { + if (($model = Country::findOne(['code' => $code])) !== null) { + return $model; + } + + throw new NotFoundHttpException('The requested page does not exist.'); + } +} diff --git a/controllers/SiteController.php b/controllers/SiteController.php index 67c3f50..d93a960 100644 --- a/controllers/SiteController.php +++ b/controllers/SiteController.php @@ -2,6 +2,7 @@ namespace app\controllers; +use app\models\EntryForm; use Yii; use yii\filters\AccessControl; use yii\web\Controller; @@ -125,4 +126,24 @@ class SiteController extends Controller { return $this->render('about'); } + + /** + * Displays hello page. + * + * @return string + */ + public function actionSay($message = 'hello') + { + return $this->render('say', ['message' => $message]); + } + + public function actionEntry() + { + $model = new EntryForm(); + if ($model->load(Yii::$app->request->post()) && $model->validate()) { + return $this->render('entry-confirm', ['model' => $model]); + } else { + return $this->render('entry', ['model' => $model]); + } + } } diff --git a/controllers/UserController.php b/controllers/UserController.php new file mode 100644 index 0000000..6a932cc --- /dev/null +++ b/controllers/UserController.php @@ -0,0 +1,195 @@ + [ + 'class' => VerbFilter::className(), + 'actions' => [ + 'delete' => ['POST'], + ], + ], + ] + ); + } + + /** + * Lists all User models. + * + * @return string + */ + public function actionIndex() + { + $searchModel = new UserSearch(); + $dataProvider = $searchModel->search($this->request->queryParams); + + return $this->render('index', [ + 'searchModel' => $searchModel, + 'dataProvider' => $dataProvider, + ]); + } + + /** + * Displays a single User model. + * @param int $id ID + * @return string + * @throws NotFoundHttpException if the model cannot be found + */ + public function actionView($id) + { + return $this->render('view', [ + 'model' => $this->findModel($id), + ]); + } + + /** + * Creates a new User model. + * If creation is successful, the browser will be redirected to the 'view' page. + * @return string|\yii\web\Response + */ + public function actionCreate() + { + $model = new User(); + + if ($this->request->isPost) { + if ($model->load($this->request->post()) && $model->save()) { + return $this->redirect(['view', 'id' => $model->id]); + } + } else { + $model->loadDefaultValues(); + } + + return $this->render('create', [ + 'model' => $model, + ]); + } + + /** + * Updates an existing User model. + * If update is successful, the browser will be redirected to the 'view' page. + * @param int $id ID + * @return string|\yii\web\Response + * @throws NotFoundHttpException if the model cannot be found + */ + public function actionUpdate($id) + { + $model = $this->findModel($id); + + if ($this->request->isPost && $model->load($this->request->post()) && $model->save()) { + return $this->redirect(['view', 'id' => $model->id]); + } + + return $this->render('update', [ + 'model' => $model, + ]); + } + + /** + * Deletes an existing User model. + * If deletion is successful, the browser will be redirected to the 'index' page. + * @param int $id ID + * @return \yii\web\Response + * @throws NotFoundHttpException if the model cannot be found + */ + public function actionDelete($id) + { + $this->findModel($id)->delete(); + + return $this->redirect(['index']); + } + + /** + * Finds the User model based on its primary key value. + * If the model is not found, a 404 HTTP exception will be thrown. + * @param int $id ID + * @return User the loaded model + * @throws NotFoundHttpException if the model cannot be found + */ + protected function findModel($id) + { + if (($model = User::findOne(['id' => $id])) !== null) { + return $model; + } + + throw new NotFoundHttpException('The requested page does not exist.'); + } + + /** + * Displays the login page. + * @return string|\yii\web\Response + */ + public function actionLogin() + { + if (!Yii::$app->user->isGuest) { + return $this->goHome(); + } + + $model = new User(); + + if ($model->load(Yii::$app->request->post()) && $model->validate()) { + if ($model->login()) { + return $this->goBack(); + } else { + Yii::$app->session->setFlash('error', 'Invalid username or password.'); + } + } + + return $this->render('login', [ + 'model' => $model, + ]); + } + + /** + * Logs out the current user. + * @return \yii\web\Response + */ + public function actionLogout() + { + Yii::$app->user->logout(); + + return $this->goHome(); + } + + /** + * Displays the registration page. + * @return string|\yii\web\Response + */ + public function actionRegister() + { + $model = new User(); + + if ($model->load(Yii::$app->request->post()) && $model->validate()) { + $model->password = Yii::$app->security->generatePasswordHash($model->password); + $model->auth_key = Yii::$app->security->generateRandomString(); + if ($model->save()) { + Yii::$app->session->setFlash('success', 'Registration successful. You can now log in.'); + return $this->redirect(['login']); + } else { + Yii::$app->session->setFlash('error', 'Failed to register user.'); + } + } + + return $this->render('register', [ + 'model' => $model, + ]); + } +} diff --git a/models/Country.php b/models/Country.php new file mode 100644 index 0000000..d64380c --- /dev/null +++ b/models/Country.php @@ -0,0 +1,49 @@ + 2], + [['name'], 'string', 'max' => 52], + [['code'], 'unique'], + ]; + } + + /** + * {@inheritdoc} + */ + public function attributeLabels() + { + return [ + 'code' => 'Code', + 'name' => 'Name', + 'population' => 'Population', + ]; + } +} diff --git a/models/CountrySearch.php b/models/CountrySearch.php new file mode 100644 index 0000000..db1f878 --- /dev/null +++ b/models/CountrySearch.php @@ -0,0 +1,69 @@ + $query, + ]); + + $this->load($params); + + if (!$this->validate()) { + // uncomment the following line if you do not want to return any records when validation fails + // $query->where('0=1'); + return $dataProvider; + } + + // grid filtering conditions + $query->andFilterWhere([ + 'population' => $this->population, + ]); + + $query->andFilterWhere(['like', 'code', $this->code]) + ->andFilterWhere(['like', 'name', $this->name]); + + return $dataProvider; + } +} diff --git a/models/EntryForm.php b/models/EntryForm.php new file mode 100644 index 0000000..079d396 --- /dev/null +++ b/models/EntryForm.php @@ -0,0 +1,18 @@ + [ - 'id' => '100', - 'username' => 'admin', - 'password' => 'admin', - 'authKey' => 'test100key', - 'accessToken' => '100-token', - ], - '101' => [ - 'id' => '101', - 'username' => 'demo', - 'password' => 'demo', - 'authKey' => 'test101key', - 'accessToken' => '101-token', - ], - ]; - + /** + * {@inheritdoc} + */ + public static function tableName() + { + return 'user'; + } /** * {@inheritdoc} */ + public function rules() + { + return [ + [['username', 'password'], 'required', 'on' => 'login'], + [['username', 'password', 'email'], 'required', 'on' => 'register'], + [['username', 'password', 'auth_key', 'email'], 'string', 'max' => 255], + [['status'], 'integer'], + ]; + } + + /** + * {@inheritdoc} + */ + public function attributeLabels() + { + return [ + 'id' => 'ID', + 'username' => 'Username', + 'password' => 'Password', + 'auth_key' => 'Auth Key', + 'email' => 'Email', + 'status' => 'Status', + ]; + } + /** + * Finds an identity by the given ID. + * + * @param string|int $id the ID to be looked for + * @return IdentityInterface|null the identity object that matches the given ID. + */ public static function findIdentity($id) { - return isset(self::$users[$id]) ? new static(self::$users[$id]) : null; + return static::findOne($id); } /** - * {@inheritdoc} + * Finds an identity by the given token. + * + * @param mixed $token the token to be looked for + * @param mixed $type the type of the token. The value of this parameter depends on the implementation. + * For example, [[\yii\filters\auth\HttpBearerAuth]] will set this parameter to be `yii\filters\auth\HttpBearerAuth`. + * @return IdentityInterface|null the identity object that matches the given token. */ public static function findIdentityByAccessToken($token, $type = null) { - foreach (self::$users as $user) { - if ($user['accessToken'] === $token) { - return new static($user); - } - } - + // This method is not needed if you don't use access tokens for authentication. return null; } /** - * Finds user by username + * Returns the ID of the user. * - * @param string $username - * @return static|null - */ - public static function findByUsername($username) - { - foreach (self::$users as $user) { - if (strcasecmp($user['username'], $username) === 0) { - return new static($user); - } - } - - return null; - } - - /** - * {@inheritdoc} + * @return string|int the ID of the user */ public function getId() { @@ -76,29 +88,23 @@ class User extends \yii\base\BaseObject implements \yii\web\IdentityInterface } /** - * {@inheritdoc} + * Returns an auth key used to authenticate cookie-based login. + * + * @return string the auth key */ public function getAuthKey() { - return $this->authKey; + return $this->auth_key; } /** - * {@inheritdoc} + * Validates the given auth key. + * + * @param string $authKey the given auth key + * @return bool whether the given auth key is valid. */ public function validateAuthKey($authKey) { - return $this->authKey === $authKey; + return $this->getAuthKey() === $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; - } -} +} \ No newline at end of file diff --git a/models/UserSearch.php b/models/UserSearch.php new file mode 100644 index 0000000..f98bd33 --- /dev/null +++ b/models/UserSearch.php @@ -0,0 +1,72 @@ + $query, + ]); + + $this->load($params); + + if (!$this->validate()) { + // uncomment the following line if you do not want to return any records when validation fails + // $query->where('0=1'); + return $dataProvider; + } + + // grid filtering conditions + $query->andFilterWhere([ + 'id' => $this->id, + 'status' => $this->status, + ]); + + $query->andFilterWhere(['like', 'username', $this->username]) + ->andFilterWhere(['like', 'password', $this->password]) + ->andFilterWhere(['like', 'auth_key', $this->auth_key]) + ->andFilterWhere(['like', 'email', $this->email]); + + return $dataProvider; + } +} diff --git a/views/country/_form.php b/views/country/_form.php new file mode 100644 index 0000000..98ecd39 --- /dev/null +++ b/views/country/_form.php @@ -0,0 +1,27 @@ + + +
+ = Html::a('Create Country', ['create'], ['class' => 'btn btn-success']) ?> +
+ + render('_search', ['model' => $searchModel]); ?> + + = GridView::widget([ + 'dataProvider' => $dataProvider, + 'filterModel' => $searchModel, + 'columns' => [ + ['class' => 'yii\grid\SerialColumn'], + + 'code', + 'name', + 'population', + [ + 'class' => ActionColumn::className(), + 'urlCreator' => function ($action, Country $model, $key, $index, $column) { + return Url::toRoute([$action, 'code' => $model->code]); + } + ], + ], + ]); ?> + + ++ = Html::a('Update', ['update', 'code' => $model->code], ['class' => 'btn btn-primary']) ?> + = Html::a('Delete', ['delete', 'code' => $model->code], [ + 'class' => 'btn btn-danger', + 'data' => [ + 'confirm' => 'Are you sure you want to delete this item?', + 'method' => 'post', + ], + ]) ?> +
+ + = DetailView::widget([ + 'model' => $model, + 'attributes' => [ + 'code', + 'name', + 'population', + ], + ]) ?> + +你提交了以下信息
++ = Html::a('Create User', ['create'], ['class' => 'btn btn-success']) ?> +
+ + render('_search', ['model' => $searchModel]); ?> + + = GridView::widget([ + 'dataProvider' => $dataProvider, + 'filterModel' => $searchModel, + 'columns' => [ + ['class' => 'yii\grid\SerialColumn'], + + 'id', + 'username', + 'password', + 'auth_key', + 'email:email', + //'status', + [ + 'class' => ActionColumn::className(), + 'urlCreator' => function ($action, User $model, $key, $index, $column) { + return Url::toRoute([$action, 'id' => $model->id]); + } + ], + ], + ]); ?> + + ++ = Html::a('Update', ['update', 'id' => $model->id], ['class' => 'btn btn-primary']) ?> + = Html::a('Delete', ['delete', 'id' => $model->id], [ + 'class' => 'btn btn-danger', + 'data' => [ + 'confirm' => 'Are you sure you want to delete this item?', + 'method' => 'post', + ], + ]) ?> +
+ + = DetailView::widget([ + 'model' => $model, + 'attributes' => [ + 'id', + 'username', + 'password', + 'auth_key', + 'email:email', + 'status', + ], + ]) ?> + +