Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ParentId field snippet #97

Open
yujin1st opened this issue Apr 30, 2016 · 0 comments
Open

ParentId field snippet #97

yujin1st opened this issue Apr 30, 2016 · 0 comments

Comments

@yujin1st
Copy link

In a few projects I had a form with parent category search field, and you need to move node or insert in exact position while creating or updating model. If you don't use nested sets and use only parentId field there is no problem at all, but with pure nested sets you should choose what operation to use in every case. After all I've come to this simple solution and just want to share it.

For simplicity you can add parentId field (not necessary to database!) and use this overridden behavior.
After this you can set parentId value and use just a save() method anywhere instead of many others.

Overridden behavior

class NestedSetsBehavior extends \creocoder\nestedsets\NestedSetsBehavior
{
   /**
   * Simplifying saving by checking parentId field if operation is not set
   * or modifying field value otherwise
   */
  protected function checkOperation() {
    /** @var Category $owner */
    $owner = $this->owner;

    if (!in_array($this->operation, [
      self::OPERATION_MAKE_ROOT,
      self::OPERATION_PREPEND_TO,
      self::OPERATION_APPEND_TO,
      self::OPERATION_INSERT_BEFORE,
      self::OPERATION_INSERT_AFTER,
    ])
    ) {
      if ($owner->parentId) {
        $this->operation = self::OPERATION_APPEND_TO;
        $this->node = Category::findOne($owner->parentId);
      } else {
        $owner->parentId = null;
        $this->operation = self::OPERATION_MAKE_ROOT;
      }
    }

    if ($this->operation == self::OPERATION_MAKE_ROOT) {
      $owner->parentId = null;
    } else if ($this->node && in_array($this->operation, [
        self::OPERATION_PREPEND_TO,
        self::OPERATION_APPEND_TO,
      ])
    ) {
      $owner->parentId = $this->node->id;
    } else if ($this->node && in_array($this->operation, [
        self::OPERATION_INSERT_BEFORE,
        self::OPERATION_INSERT_AFTER,
      ])
    ) {
      $owner->parentId = $this->node->parentId;
    }

  }

  /**
   *
   * @inheritDoc
   */
  public function beforeInsert() {
    $this->checkOperation();
    parent::beforeInsert();
  }

  /**
   * @inheritDoc
   */
  public function beforeUpdate() {
    $this->checkOperation();
    parent::beforeUpdate();
  }
}

In controller

  /**
   * Creates a new Category model.
   *
   * @return mixed
   */
  public function actionCreate() {
    $model = new Category([]);

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

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

  }


  /**
   * Search for typeahead
   *
   * @param $term
   * @return array
   */
  public function actionSearch($term) {
    $data = [];
    $term = trim($term);
    /** @var Category[] $categories */
    $categories = Category::find()
      ->orFilterWhere(['like', 'title', $term])
      ->orderBy('deleted ASC')->limit(10)->all();
    if ($categories) foreach ($categories as $category) {
      $data[] = [
        'value' => $category->title,
        'id' => $category->id,
      ];
    }


    Yii::$app->response->format = Response::FORMAT_JSON;
    return $data;
  }

In view

  <?= Html::activeHiddenInput($model, 'parentId') ?>
  <?php $help = 'Leave empty for inserting as root' ?>
  <?= $form->field($model, 'parentSearch', [])
    ->hint($help)
    ->widget(\kartik\typeahead\Typeahead::className(), [
      'options' => ['placeholder' => 'Type for search', 'value' => $model->parentId ? $model->parent->title : ''],
      'pluginOptions' => ['highlight' => true],
      'pluginEvents' => [
        "typeahead:select" => 'function(ev, obj) {
          $("#' . Html::getInputId($model, 'parentId') . '").val(obj.id)
          return false ; 
        }',
      ],
      'dataset' => [
        [
          'datumTokenizer' => "Bloodhound.tokenizers.obj.whitespace('value')",
          'display' => 'value',
          'remote' => [
            'url' => \yii\helpers\Url::to(['category/search', 'new' => 1]) . '&term=%QUERY',
            'wildcard' => '%QUERY'
          ],
          'templates' => [
            'notFound' => '<div class="text-danger" style="padding:0 8px">Cannot find category</div>',
          ]
        ]
      ]
    ]) ?>

PS: i asked this question some time ago here, and see people looking out here and as i'm not the only one, who wonders, just wanted to share my solution of this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant