Yii
is a high-performance, component-based PHP framework for rapid development of modern web applications.
Today, based on the idea of Yii2
Yii2
Todo List
from 0 to 1, and complete the following functions:
- May be based on a
key
createTodo Item
, then according tokey
query correspondingTodo Item
. - You can top, complete, delete a single
Todo Item
, the topTodo Item
will be arranged at the front, and the completedTodo Item
will be arranged at the back.
Initialize the YII repository
Use the following command to initialize a warehouse of YII
composer create-project --prefer-dist yiisoft/yii2-app-basic basic
However, my mac
to the network through this method and fails to install some dependencies, so I choose the second method here. (as follows)
Download the archive at yiiframework and unzip it into the project directory where you want to place it.
After downloading and decompressing, you need to modify the config/web.php
file and cookieValidationKey
configuration item (just enter a value) so that the project can start normally.
After the project is initialized, let's run the project with the following command.
php yii serve --port=8888
Then we open http://localhost:8888 and see that our page has been successfully started! (As shown below)
Initialize the data model
Next, let's initialize our data model.
The fields we need to create are the following:
- id: self-incrementing primary key;
- key: Todo's key;
- title: Todo's title;
- is_completed: Whether Todo is completed;
- is_top: Whether Todo is on top;
- is_deleted: Whether Todo is deleted;
And above these fields, we have the most scenes by key
to fish out the relevant Todo Item
, so it should give key
establish a common index.
In summary, our sql
statement should look like this:
CREATE TABLE IF NOT EXISTS `todos` (
`id` int PRIMARY KEY AUTO_INCREMENT,
`key` varchar(64) NOT NULL DEFAULT '',
`title` varchar(64) NOT NULL DEFAULT '',
`is_top` tinyint(1) NOT NULL DEFAULT 0,
`is_completed` tinyint(1) NOT NULL DEFAULT 0,
`is_deleted` tinyint(1) NOT NULL DEFAULT 0,
index `key`(`key`)
) engine=InnoDB CHARSET=utf8;
SQL
in the database to create the corresponding data table.
Then, we can also view the index we created with the following statement.
SHOW INDEX FROM `todos`;
Handling Todo business logic
After the data table is successfully created, we are ready to start writing the business logic related to Todo
Before that, we also need to do some Yii
configuration initialization work.
Initialize Yii configuration
First of all, our php
service needs to connect to the database, so you need to configure your database connection first, which is config/db.php
:
- Database configuration
<?php
return [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=[mysql服务器地址];port=[mysql端口];dbname=[数据库名称]',
'username' => '[数据库用户名]',
'password' => '[数据库密码]',
'charset' => 'utf8',
'attributes' => [
// 查询时将 int 类型按原类型返回
PDO::ATTR_STRINGIFY_FETCHES => false,
PDO::ATTR_EMULATE_PREPARES => false
]
];
- URL beautification configuration
Then, let's configure URL
beautification, so that we can restful
style, and adjust config/web.php
in urlManager
. (as follows)
'urlManager' => [
'enablePrettyUrl' => true,
'enableStrictParsing' => false,
'showScriptName' => false,
'rules' => [
],
],
- JSON input parameter configuration
Then, we also need to modify request
in order to accept the application/json
parameters of 061fb8b89bc87d.
'components' => [
...
'request' => [
'parsers' => [
'application/json' => 'yii\web\JsonParser',
]
],
...
]
After modifying the configuration, you can restart your project.
Create TodoModel
+ TodoRepository
+ TodoService
+ TodoController
Let's create Todo
data entity class - TodoModel
, this model will run through Todo List
entire life cycle.
<?php
namespace app\models;
use Yii;
use Yii\base\Model;
class TodoModel extends Model {
public $id;
public $key;
public $title;
public $is_top;
public $is_completed;
public $is_deleted;
}
Then, we create TodoRepository
for data persistence. - SQL is written here.
<?php
namespace app\repositories;
use app\models\TodoModel;
class TodoRepository {
public static function selectAll(TodoModel $todo) {
}
public static function insertOne(TodoModel $todo) {
}
public static function deleteOne(TodoModel $todo) {
}
public static function updateOne(TodoModel $todo) {
}
}
Next, let's create TodoService
to handle business logic. - All business logic is placed here.
<?php
namespace app\services;
use app\models\TodoModel;
use app\repositories\TodoRepository;
class TodoService {
public function getAllTodo(TodoModel $model) {
return TodoRepository::selectAll($model);
}
public function addTodo(TodoModel $model) {
}
public function topTodo(TodoModel $model) {
}
public function completeTodo(TodoModel $model) {
}
public function deleteTodo(TodoModel $model) {
}
}
Finally, we create TodoController
, which is used to control business processes and handle interface requests. - The logic for interacting with the client is placed here.
<?php
namespace app\controllers;
use Yii;
use yii\rest\ActiveController;
use yii\web\Response;
use app\services\TodoService;
use app\models\TodoModel;
class TodoController extends ActiveController
{
public TodoService $todoService;
public function __construct($id, $module, $config = [])
{
parent::__construct($id, $module, $config);
this.$todoService = new TodoService();
}
// 将响应数据转成 JSON
public function behaviors()
{
return [
[
'class' => \yii\filters\ContentNegotiator::className(),
'only' => ['index', 'view'],
'formats' => [
'application/json' => \yii\web\Response::FORMAT_JSON,
],
],
];
}
public function actionGetTodoList() {
}
}
After TodoModel
basic 061fb8b89bc9b6 + TodoRepository
+ TodoService
+ TodoController
, that is, MVC
model, we are ready to start adding real and effective business logic.
Query key
corresponding to Todo List
We are now ready to query the corresponding todo
list key
We first edit TodoRepository
of selectAll
, and write the corresponding query logic SQL
class TodoRepository {
/**
* @throws \yii\db\Exception
*/
public static function selectAll(TodoModel $todo) {
$db = Yii::$app->db;
// 组装 SQL 语句,查询对应 key 且未删除的数据
// 查询的数据按照 `是否完成` 升序排列,按照 `是否置顶` 降序排列
$sql = "SELECT *
FROM `todos`
WHERE `key` = :code AND `is_deleted` = 0
ORDER BY is_completed ASC, is_top DESC";
return $db->createCommand($sql)->bindValue(':code', $todo->key)->queryAll();
}
//...
}
In TodoRepository
of SQL
after the statement editing is complete, we can try to execute in the database. (As shown below)
As can be seen from the above figure, the SQL
as we expected - using key
as the index, only 4 pieces of data are retrieved (the database has 10 pieces of data at this time).
ThisSQL
also involvesUsing filesort
, I have not thought of a better optimization plan, you can try to optimize this SQL.
We edit TodoController
of actionGetTodoList
method can ( TodoService
not need to change).
public function actionGetTodoList() {
$model = new TodoModel();
$params = Yii::$app->request->get();
// 取出 query 参数中的 key 字段
$model->key = $params['key'];
return $this->todoService->getAllTodo($model);
}
After the logic is added, open the page http://localhost:8888/todo/get-todo-list?key=test
verify the effect. (As shown below)
As you can see from the image above, the data is returned as we expected it to be filtered and sorted!
Completion of the remaining business logic - additions, deletions and modifications
Next, just add the logic of adding, deleting and modifying in turn. This should be the simplest and most classic
CRUD
. (as follows)
TodoModel.php
<?php
namespace app\models;
use Yii;
use yii\base\Model;
class TodoModel extends Model
{
public $id;
public $key = '';
public $title = '';
public $is_top = 0;
public $is_completed = 0;
public $is_deleted = 0;
public function rules()
{
return [
[['id', 'key', 'title'], 'required']
];
}
}
TodoRepository.php
<?php
namespace app\repositories;
use Yii;
use app\models\TodoModel;
class TodoRepository
{
/**
* @throws \yii\db\Exception
*/
public static function selectAll(TodoModel $todo)
{
$db = Yii::$app->db;
// 组装 SQL 语句,查询对应 key 且未删除的数据
// 查询的数据按照 `是否完成` 升序排列,按照 `是否置顶` 降序排列
$sql = "SELECT *
FROM `todos`
WHERE `key` = :code AND `is_deleted` = 0
ORDER BY is_completed ASC, is_top DESC";
return $db->createCommand($sql)->bindValue(':code', $todo->key)->queryAll();
}
/**
* @throws \yii\db\Exception
*/
public static function insertOne(TodoModel $todo)
{
$db = Yii::$app->db;
return $db->createCommand()->insert('todos', $todo)->execute();
}
/**
* @throws \yii\db\Exception
*/
public static function updateOne(array $todoData, string $id)
{
$db = Yii::$app->db;
return $db
->createCommand()
->update('todos', $todoData, "id = :id")
->bindValue("id", $id)
->execute();
}
}
TodoService.php
<?php
namespace app\services;
use app\models\TodoModel;
use app\repositories\TodoRepository;
class TodoService
{
public function getAllTodo(TodoModel $model)
{
return TodoRepository::selectAll($model);
}
public function addTodo(TodoModel $model)
{
return TodoRepository::insertOne($model);
}
public function topTodo(TodoModel $model)
{
return TodoRepository::updateOne([
'is_top' => 1
], $model->id);
}
public function completeTodo(TodoModel $model)
{
return TodoRepository::updateOne([
'is_completed' => 1
], $model->id);
}
public function deleteTodo(TodoModel $model)
{
return TodoRepository::updateOne([
'is_deleted' => 1
], $model->id);
}
}
TodoController.php
<?php
namespace app\controllers;
use Yii;
use yii\web\Controller;
use app\services\TodoService;
use app\models\TodoModel;
class TodoController extends Controller
{
public $todoService;
public $enableCsrfValidation = false;
public function __construct($id, $module, $config = [])
{
parent::__construct($id, $module, $config);
$this->todoService = new TodoService();
}
// 将响应数据转成 JSON
public function behaviors()
{
return [
[
'class' => \yii\filters\ContentNegotiator::className(),
'formats' => [
'application/json' => \yii\web\Response::FORMAT_JSON,
],
],
];
}
public function actionGetTodoList()
{
$model = new TodoModel();
$params = Yii::$app->request->get();
// 取出 query 参数中的 key 字段
$model->key = $params['key'];
return [
'code' => 0,
'data' => $this->todoService->getAllTodo($model)
];
}
public function actionAdd()
{
$model = new TodoModel();
$params = Yii::$app->request->post();
$model->key = $params['key'];
$model->title = $params['title'];
$this->todoService->addTodo($model);
return ['code' => 0];
}
public function actionTop()
{
$model = new TodoModel();
$params = Yii::$app->request->post();
$model->id = $params['id'];
$this->todoService->topTodo($model);
return ['code' => 0];
}
public function actionComplete()
{
$model = new TodoModel();
$params = Yii::$app->request->post();
$model->id = $params['id'];
$this->todoService->completeTodo($model);
return ['code' => 0];
}
public function actionDelete()
{
$model = new TodoModel();
$params = Yii::$app->request->post();
$model->id = $params['id'];
$this->todoService->deleteTodo($model);
return ['code' => 0];
}
}
In this way, our Todo List
system is basically completed, and it has completed the following functions:
- May be based on a
key
createTodo Item
, then according tokey
query correspondingTodo Item
. - You can top, complete, delete a single
Todo Item
, the topTodo Item
will be arranged at the front, and the completedTodo Item
will be arranged at the back.
Of course, we also need to consider parameter verification, optimization of big data queries, simpler parameter binding, etc., which will not be expanded here, and may be explained in a new article.
Deploy the application
Now, let's Todo List
system online.
Start the Docker container
Yii2
is very simple because Yii has built-in docker-compose
configuration file.
So, we just need to run docker-compose up -d
in the folder to start a docker service. (As shown below)
Now, let's modify docker-compose.yml
and change it to a special port - 9999
.
ports:
- '9999:80'
Then, in our server (my server is Alibaba Cloud ECS), we pull down the corresponding warehouse code and run docker-compose up -d
start the container.
Configure Nginx
After the service starts, we need to configure nginx
, we will specify the domain name request hacker.jt-gmall.com
forwarded to 9999
port.
Then, nginx
to allow front-end cross-domain requests (last few lines).
server {
listen 443;
server_name hacker.jt-gmall.com;
ssl on;
ssl_certificate /https/hacker.jt-gmall.com.pem;
ssl_certificate_key /https/hacker.jt-gmall.com.key;
ssl_session_timeout 5m;
ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
ssl_protocols SSLv2 SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
location / {
index index.html index.jsp;
client_max_body_size 300m;
client_body_buffer_size 128k;
proxy_connect_timeout 600;
proxy_read_timeout 600;
proxy_send_timeout 600;
proxy_buffer_size 64k;
proxy_buffers 4 64k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_pass http://127.0.0.1:9999;
add_header "Access-Control-Allow-Origin" "*"; # 全局变量获得当前请求origin,带cookie的请求不支持*
add_header "Access-Control-Allow-Methods" "*"; # 允许请求方法
add_header "Access-Control-Allow-Headers" "*"; # 允许请求的 header
# 如果是 OPTIONS 请求,则返回 204
if ($request_method = 'OPTIONS') {
return 204;
}
}
}
Install dependencies
After the service is started and nginx
is configured, the following error may appear.
This is because Git
version management, it ignores Yii
of vendor
directory, we only need to use composer
will depend re-install it again, run the following command.
composer update
composer install
Since
config/db.php
contains database connection information, I did not put it in theGit
warehouse.If you are using my
demo
, please complete this file as well.
Then, we open the browser and enter https://hacker.jt-gmall.com/todo/get-todo-list?key=test see the effect! (As shown below)
You're done!
summary
In this article, I wrote an article about my experience of Yii
build a basic Todo List
After the actual operation, I found that Yii
build a server-side business site, and the classic MVC
mode is also relatively easy to understand.
In subsequent articles, I may Yii
the advanced use of 061fb8b89bcff7.
Finally, attach the Demo address this experience.
one last thing
If you have seen this, I hope you will give a like and go~
Your likes are the greatest encouragement to the author, and can also allow more people to see this article!
If you think this article is helpful to you, please help to light up star
github to encourage it!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。