How to create tags for posts in yii2

I am trying to create a simple cms with yii2 In that i have created a post with wysiwig editor Now i want to add taggable functionality to the same post how can i do that i gone through some of the articles in web related to that i want add a simple taggable functionality And when user clciks on that tab they have to redirected to a page contains posts with the tags.

Here is the code for simple form

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

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

    <?= $form->field($model, 'content')->widget(CKEditor::className(), [
        'options' => ['height' => 800],
        'preset' => 'basic',
        'clientOptions' => ['height' => 400]
    ]) ?>

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

    <?= $form->field($model, 'date')->textInput() ?>

    <div class="form-group">
        <?= Html::submitButton('Save', ['class' => 'btn btn-success']) ?>
    </div>

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

At first you can try this extension for implementing taggable functionality:
https://github.com/2amigos/yii2-taggable-behavior

And then it should be easy to write a controller action for viewing all posts with the same tag.

Thank you :slight_smile:

I have created two tables as the post says which is as follow.

CREATE TABLE `tags` (
  `id` int(250) NOT NULL,
  `frequency` varchar(500) NOT NULL,
  `name` varchar(250) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

And the second one

CREATE TABLE `tag_assign` (
  `tag_id` int(250) NOT NULL,
  `article_id` int(250) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
COMMIT;

Also I have created a tags model in common folder of yii2 advanced template

As well as written this part to post.

<?= $form->field($model, 'tagNames')->widget(SelectizeTextInput::className(), [
    // calls an action that returns a JSON object with matched
    // tags
    'loadUrl' => ['tag/list'],
    'options' => ['class' => 'form-control'],
    'clientOptions' => [
        'plugins' => ['remove_button'],
        'valueField' => 'name',
        'labelField' => 'name',
        'searchField' => ['name'],
        'create' => true,
    ],
])->hint('Use commas to separate tags') ?>

It is giving the request properly The console is telling me

GET http://localhost/counter/advanced/backend/web/index.php/tags/list?query=ds%20 404 (Not Found)

Where will i write down the rest of the code which model and controllers?

From this github document

Did you create actionList in your Controller ? (if you are following example for GitHub without changes then it is named TagController)

public function actionList($query)
{
$models = Tag::findAllByName($query);
$items = [];

foreach ($models as $model) {
    $items[] = ['name' => $model->name];
}
// We know we can use ContentNegotiator filter
// this way is easier to show you here :)
Yii::$app->response->format = Response::FORMAT_JSON;

return $items;
}
1 Like

I have created a tags controller using gii and added following lines of code

  public function actionList($query)
    {
      $models = Tag::findAllByName($query);
      $items = [];

      foreach ($models as $model) {
          $items[] = ['name' => $model->name];
      }
      // We know we can use ContentNegotiator filter
      // this way is easier to show you here :)
      Yii::$app->response->format = Response::FORMAT_JSON;

      return $items;
    }

From the console i am getting the following

GET http://localhost/counter/advanced/backend/web/index.php/tags/list?query=fd 500 (Internal Server Error)

If i visit the url it is showing me

## Call to undefined method common\models\Tags::findAllByName()

My tagModel

<?php

namespace common\models;

use Yii;
//For ajax tagging
use dosamigos\taggable\Taggable;

/**
 * This is the model class for table "tags".
 *
 * @property int $id
 * @property string $frequency
 * @property string $name
 */
class Tag extends \yii\db\ActiveRecord
{
    /**
     * {@inheritdoc}
     */
    public static function tableName()
    {
        return 'tags';
    }

    /**
     * {@inheritdoc}
     */
    public function rules()
    {
        // return [
        //     [['frequency', 'name'], 'required'],
        //     [['frequency'], 'string', 'max' => 500],
        //     [['name'], 'string', 'max' => 250],
        // ];
       return [
           // ...
           [['tagNames'], 'safe'],
           // ...
       ];
    }

    /**
     * {@inheritdoc}
     */
    public function attributeLabels()
    {
        return [
            'id' => 'ID',
            'frequency' => 'Frequency',
            'name' => 'Name',
        ];
    }

    //For taggable content
    public function behaviors() {
       return [
           [
               'class' => Taggable::className(),
           ],
       ];
   }

    public function getTags()
{
    return $this->hasMany(Tag::className(), ['id' => 'tag_id'])->viaTable('tag_assign', ['article_id' => 'id']);
}

}

And my tag controller

<?php

namespace backend\controllers;

use Yii;
use common\models\Tag;
use common\models\searchTag;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;

/**
 * TagController implements the CRUD actions for Tag model.
 */
class TagController extends Controller
{
    /**
     * {@inheritdoc}
     */
    public function behaviors()
    {
        return [
            'verbs' => [
                'class' => VerbFilter::className(),
                'actions' => [
                    'delete' => ['POST'],
                ],
            ],
        ];
    }

    /**
     * Lists all Tag models.
     * @return mixed
     */
    public function actionIndex()
    {
        $searchModel = new searchTag();
        $dataProvider = $searchModel->search(Yii::$app->request->queryParams);

        return $this->render('index', [
            'searchModel' => $searchModel,
            'dataProvider' => $dataProvider,
        ]);
    }

    public function actionList($query)
    {
        $models = Tag::findAllByName($query);
        $items = [];

        foreach ($models as $model) {
            $items[] = ['name' => $model->name];
        }
        // We know we can use ContentNegotiator filter
        // this way is easier to show you here :)
        Yii::$app->response->format = Response::FORMAT_JSON;

        return $items;
    }

    /**
     * Displays a single Tag model.
     * @param integer $id
     * @return mixed
     * @throws NotFoundHttpException if the model cannot be found
     */
    public function actionView($id)
    {
        return $this->render('view', [
            'model' => $this->findModel($id),
        ]);
    }

    /**
     * Creates a new Tag model.
     * If creation is successful, the browser will be redirected to the 'view' page.
     * @return mixed
     */
    public function actionCreate()
    {
        $model = new Tag();

        if ($model->load(Yii::$app->request->post()) && $model->save()) {
            return $this->redirect(['view', 'id' => $model->id]);
        }

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

    /**
     * Updates an existing Tag model.
     * If update is successful, the browser will be redirected to the 'view' page.
     * @param integer $id
     * @return mixed
     * @throws NotFoundHttpException if the model cannot be found
     */
    public function actionUpdate($id)
    {
        $model = $this->findModel($id);

        if ($model->load(Yii::$app->request->post()) && $model->save()) {
            return $this->redirect(['view', 'id' => $model->id]);
        }

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

    /**
     * Deletes an existing Tag model.
     * If deletion is successful, the browser will be redirected to the 'index' page.
     * @param integer $id
     * @return mixed
     * @throws NotFoundHttpException if the model cannot be found
     */
    public function actionDelete($id)
    {
        $this->findModel($id)->delete();

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

    /**
     * Finds the Tag model based on its primary key value.
     * If the model is not found, a 404 HTTP exception will be thrown.
     * @param integer $id
     * @return Tag the loaded model
     * @throws NotFoundHttpException if the model cannot be found
     */
    protected function findModel($id)
    {
        if (($model = Tag::findOne($id)) !== null) {
            return $model;
        }

        throw new NotFoundHttpException('The requested page does not exist.');
    }
}

Also i found this in github

As mentioned in linked GiHub issue discussion by user Firvagor, you need to insert something like this to your Tag model:

public function findAllByName($name)
{
    return Tag::find()->where('name LIKE :query')
                      ->addParams([':query'=>"%$name%"])
                      ->all();
}

Also, I noticed that your model and controller are named Tag and TagContoller but the error says that Tags model is missing that method. Double-check for any typos.

Yeah i have done that it is fetching data from the db but it is not getting saved in tags table.

Check app.log for any errors, also look at the comments in the git hub issue that you post earlier. Mainly these:
https://github.com/2amigos/yii2-taggable-behavior/issues/12#issuecomment-74066981
https://github.com/2amigos/yii2-taggable-behavior/issues/12#issuecomment-74529956
https://github.com/2amigos/yii2-taggable-behavior/issues/12#issuecomment-74383485
Check if your models and controllers looks like theirs.