博客文章 CRUD

文章

文章发布管理是博客系统中比较重要的功能了,涉及到文章logo图片上传,富文本编辑器整合等相关的内容

数据模型

根据需求定义如下字段:

CREATE TABLE `article` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `title` varchar(255) NOT NULL DEFAULT '' COMMENT '标题',
  `author` varchar(100) NOT NULL DEFAULT '佚名' COMMENT '作者',
  `category_id` int(11) NOT NULL COMMENT '分类',
  `content` longtext COMMENT '内容',
  `image_url` varchar(255) NOT NULL DEFAULT '' COMMENT '图片',
  `is_valid` tinyint(4) NOT NULL DEFAULT '1' COMMENT '是否有效:1-是 2-否',
  `created_at` datetime DEFAULT NULL COMMENT '创建时间',
  `updated_at` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='文章表';

代码生成和创建菜单

跟之前一样,通过 Gii 生成模型:Article 和对应的 CRUD 代码,做一下中文替换,在内容管理下新建一下菜单:站点》内容管理》文章管理, 具体的操作参考文章分类这一章节

调整完毕之后我们可以看到如下界面:

发布界面调整

文章发布主要有以下几个功能:

  • 引入图片挂件
  • 应用 markdown 文本编辑器
  • 分类枚举

引入图片挂件

打开 backend/themes/hyii2/views/article/_form.phpimage_url 所在的行,替换成以下代码:

<?= $form->field($model, 'image_url')->widget(\Ycn\Qiniu\UploadWidget::className(),['options'=>[
    'domain' => Yii::$app->params['qiniu']['domain'].'/'
]]) ?>

应用 markdown 文本编辑器

应用 markdown 编辑器,将 content 所在的行,替换成以下代码:

<?= $form->field($model,'content')->widget(\kartik\markdown\MarkdownEditor::className(),[
    'options' => [
        'class' => 'kv-md-input',
    ]
])?>

分类枚举

分类的选择框下拉组数获取,在之前创建的分类模型中获取分类数组,在模型 Category 中添加方法:

/**
 * 分类枚举
 * 
 * @return array
 */
public static function enums()
{
    $cats = self::find()->where(['is_valid' => 1])->asArray()->all();
    return ArrayHelper::map($cats, 'id', 'name');
}

修改 category_id 所在的行项目,调整如下:

<?= $form->field($model, 'category_id')->dropDownList(\common\models\Category::enums()) ?>

调整后的 _form.php 的代码如下:

<div class="article-form" style="width: 800px;">

    <?php $form = ActiveForm::begin(); ?>

    <?= $form->field($model, 'title')->textInput(['maxlength' => true]) ?>

    <?= $form->field($model, 'author')->textInput(['maxlength' => true]) ?>

    <?= $form->field($model, 'category_id')->dropDownList(\common\models\Category::enums()) ?>

    <?= $form->field($model, 'image_url')->widget(\Ycn\Qiniu\UploadWidget::className(),['options'=>[
        'domain' => Yii::$app->params['qiniu']['domain'].'/'
    ]]) ?>

    <?= $form->field($model,'content')->widget(\kartik\markdown\MarkdownEditor::className(),[
        'options' => [
            'class' => 'kv-md-input',
        ]
    ])?>

    <?= $form->field($model, 'is_valid')->dropDownList(['1'=>'是', '2'=>'否']) ?>

    <div class="form-group">
        <?= Html::Button($model->isNewRecord ? '创建' : '更新', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary','id'=>'j-btn']) ?>
    </div>

    <?php ActiveForm::end(); ?>

</div>
<?php
$requestUrl =yii\helpers\Url::toRoute($model->isNewRecord?['create']:['update','id'=>$model->id]);
$js = <<<JS
    commit('#j-btn','{$requestUrl}'); 
JS;
$this->registerJs($js);

效果如下图所示:

发布功能开发

界面改造完成后,就要对发布的功能代码进行讲解了,发布的内容中我们先要进行图片存储,然后获取到图片地址,保存到文章数据表中。打开 backend/controller/ArticleController 对 Create 方法进行修改,代码如下:

引入所需的类:

use Ycn\Qiniu\UploadService;
use yii\web\UploadedFile;

文章创建代码:

/**
 * 添加文章接口
 *
 * @return mixed
 * @throws \Exception
 */
public function actionCreate()
{
    $model = new Article();

    if ($model->load(Yii::$app->request->post())) {

        //获取文件内容
        $file = UploadedFile::getInstance($model, 'image_url');
        if($file){

            //实例化上传对象
            $up = UploadService::getInstance(Yii::$app->params['qiniu']['ak'], Yii::$app->params['qiniu']['sk'],Yii::$app->params['qiniu']['bucket']);

            //图片上传临时路径
            $filePath= $file->tempName;

            //调用upload上传图片到七牛
            $response = $up->upload($filePath);

            $model->image_url = $response['filename'];

        }

        //文章保存
        if($model->save(true))
            return null;
    }

    return $this->renderAjax('create', [
        'model' => $model,
    ]);
}

文章编辑功能代码与文章创建代码差不多,这里就不赘述了,直接贴代码,不理解的同学可以先照着操作一遍,慢慢理解,修改 Update 的代码如下:

/**
 * 文章更新
 *
 * @param integer $id
 * @return mixed
 * @throws NotFoundHttpException
 * @throws \Exception
 */
public function actionUpdate($id)
{
    $model = $this->findModel($id);

    if ($model->load(Yii::$app->request->post())) {

        //获取文件内容
        $file = UploadedFile::getInstance($model, 'image_url');

        if($file){

            //删除原图
            $up = UploadService::getInstance(Yii::$app->params['qiniu']['ak'], Yii::$app->params['qiniu']['sk'],Yii::$app->params['qiniu']['bucket']);
            $up->delete(Yii::$app->params['qiniu']['bucket'], $model->image_url);

            //调用上传接口
            $response = $up->upload($file->tempName);

            $model->image_url = $response['filename'];

        }

        if($model->save(true))
            return null;
    }

    return $this->renderAjax('update', [
        'model' => $model,
    ]);
}

删除文章的同时也要删除图片,这样对废弃的图片就不会积累,占用不必要的资源空间,文章删除代码如下:

/**
 * 删除文章
 *
 * @param integer $id
 * @return mixed
 * @throws \Exception
 * @throws \Throwable
 */
public function actionDelete($id)
{
    try{
        $image = Article::findOne($id);
        $image->delete();

        //删除七牛图片资源
        $up = UploadService::getInstance(Yii::$app->params['qiniu']['ak'], Yii::$app->params['qiniu']['sk'],Yii::$app->params['qiniu']['bucket']);
        $up->delete(Yii::$app->params['qiniu']['bucket'], $image->image_url);

        return $this->redirect(['index']);

    }catch (\Exception $e){

        throw $e;
    }
}

文章列表

文章列表页的处理,我们需要在列表操作部分添加预览按钮,预览功能的设计是文章编辑好了之后可以在通过预览链接跳到前台的页面,因为前台我们并未介入开发,所以目前只做一个链接指向前台的地址,等后面开发前台功能的时候把对应的页面开发完成,预览功能即可实现。

列表页(backend/themes/hyii2/views/article/index.php)代码修改如下:

<div class="article-index">
    <p>
        <?= Html::a('添加文章', ['create'], ['class' => 'btn btn-success j-add', 'data-toggle' => 'modal', 'data-target' => '#page-modal']) ?>
    </p>
    <?= GridView::widget([
        'dataProvider' => $dataProvider,
        'filterModel' => $searchModel,
        'columns' => [
            ['class' => 'yii\grid\SerialColumn'],

            [
                'attribute' => 'id',
                'headerOptions' => ['width' => '5%'],
            ],
            'title',
            'author',
            [
                'attribute' => 'category_id',
                'label' => '分类',
                'value' => function($model) {
                    return \common\models\Category::enums()[$model->category_id];
                },
                'filter' => \common\models\Category::enums(),
            ],
            //'content:ntext',
            // 'image_url:url',
            [
                'attribute' => 'is_valid',
                'label' => '是否启用',
                'value' => function($model) {
                    return $model->is_valid == 1 ? '是' : '否';;
                },
                'filter' => [
                    '1'=>'是',
                    '2' => '否'
                ],
            ],
            'created_at',
            'updated_at',

            [
                'header' => '操作',
                'headerOptions' => ['width' => '10%'],
                'class' => 'yii\grid\ActionColumn',
                'template' => '{update} {delete} {preview}',
                'buttons'=>[
                    'update' => function ($url, $model, $key){
                        return \yii\bootstrap\Html::a('编辑', '#', ['class' => 'j-edit', 'data-toggle' => 'modal', 'data-target' => '#page-modal']);
                    },

                    'delete'=> function ($url, $model, $key){
                        return  Html::a('删除', ['delete', 'id'=>$model->id],[
                            'data-method'=>'post',
                            'data-confirm' => '确定删除该项?',
                        ] ) ;
                    },

                    'preview' => function ($url, $model, $key){
                        return Html::a('预览', Yii::$app->params['frontend_domain'].'/article/preview?id='.$model->id,['target'=>'_blank']);
                    }
                 ],
             ],
        ],
    ]); ?>
</div>

通过上面的课程学习,文章管理的功能就基本完成了,大家可以重复练习几次,对于细节的说明可以查询 yii2 权威指南 进行深入学习

上一篇 下一篇
yii2 入门教程 - 博客系统搭建
第1章. 基本信息
第2章. 开发环境部署