2

私は Yii 初心者で、現在 3 つのテーブルを持つタグ付けシステムに取り組んでいます。

  • 問題 (id、コンテンツ、create_d、...など)

  • タグ (id,タグ)

  • Issue_tag_map (id,tag_id_fk,issue_id_fk)

私の場合、複数のタグ ID とラベルを取得するためにMultiComplete/Views/Issue/_form拡張機能を追加しました。

およびオートコンプリートされた s をリレーションであるテーブルafterSaveに直接格納するために、関数を使用しました。Issue_idTag_idIssue_tag_mapHAS_MANY

残念ながら何も返されていません。

オートコンプリートされた Tag_ids を一時的な属性に保存し、それをモデルのafterSave() 関数に渡す方法があるのではないかと考えました。

私はしばらく探していましたが、非常に単純なステップを逃したと感じているため、これは私を夢中にさせています!

あらゆる種類のヘルプやアドバイスをいただければ幸いです。

マルチコンプリートViews/Issue/_form:

    <?php

     echo $form->labelEx($model, 'Tag');
     $this->widget('application.extension.MultiComplete', array(
    'model' => $model,
    'attribute' => '', //Was thinking of creating a temporary here
    'name' => 'tag_autocomplete',
    'splitter' => ',',
    'sourceUrl' => $this->createUrl('Issue/tagAutoComplete'),
    // Controller/Action path for action we created in step 4.
    // additional javascript options for the autocomplete plugin
    'options' => array(
        'minLength' => '2',
    ),
    'htmlOptions' => array(
        'style' => 'height:20px;',
    ),
));
echo $form->error($model, 'issue_comment_id_fk');
?>

AfterSave in/model/Issue :

    protected function afterSave() {
    parent::afterSave();

    $issue_id = Yii::app()->db->getLastInsertID();

    $tag; //here I would explode the attribute retrieved by the view form
    // an SQL with two placeholders ":issue_id" and ":tag_id"
    if (is_array($tag))
        foreach ($tag as $tag_id) {
            $sql = "INSERT INTO issue_tag_map (issue_id_fk, tag_id_fk)VALUES(:issue_id,:tag_id)";     

            $command = Yii::app()->db->createCommand($sql);
           // replace the placeholder ":issue_id" with the actual issue value

            $command->bindValue(":issue_id", $issue_id, PDO::PARAM_STR);
           // replace the placeholder ":tag_id" with the actual tag_id value

            $command->bindValue(":tag_id", $tag_id, PDO::PARAM_STR);
            $command->execute();
        }
}

これは、タグを入力するための問題モデルのオート コンプリート sourceUrl です。

    public static function tagAutoComplete($name = '') {

    $sql = 'SELECT id ,tag AS label FROM tag WHERE tag LIKE :tag';
    $name = $name . '%';
    return Yii::app()->db->createCommand($sql)->queryAll(true, array(':tag' => $name));

/controllers/IssueController の actionTagAutoComplete:

// This function will echo a JSON object 
// of this format:
// [{id:id, name: 'name'}]
function actionTagAutocomplete() {

    $term = trim($_GET['term']);
    if ($term != '') {
        $tags = issue::tagAutoComplete($term);
        echo CJSON::encode($tags);
        Yii::app()->end();
    }
}

編集

フォームのウィジェット:

   <div class="row" id="checks" >
    <?php
    echo $form->labelEx($model, 'company',array('title'=>'File Company Distrubution; Companies can be edited by Admins'));

    ?>
   <?php
    $this->widget('application.extension.MultiComplete', array(
        'model' => $model,
        'attribute' => 'company',
        'splitter' => ',',
        'name' => 'company_autocomplete',
        'sourceUrl' => $this->createUrl('becomEn/CompanyAutocomplete'),
        'options' => array(
            'minLength' => '1',
        ),
        'htmlOptions' => array(
            'style' => 'height:20px;',
            'size' => '45',
        ),
    ));
    echo $form->error($model, 'company');
    ?>
</div>

更新機能:

    $model = $this->loadModel($id);
    .....
      if (isset($_POST['News'])) {
         $model->attributes = $_POST['News'];
        $model->companies = $this->getRecordsFromAutocompleteString($_POST['News']  
       ['company']);
    ......
     ......
      getRecordsFromAutocompleteString():
  public static cordsFromAutocompleteString($string) {
    $string = trim($string);
    $stringArray = explode(", ", $string);
    $stringArray[count($stringArray) - 1] = str_replace(",", "", $stringArray[count($stringArray) - 1]);
    $criteria = new CDbCriteria();
    $criteria->select = 'id';
    $criteria->condition = 'company =:company';
    $companies = array();
    foreach ($stringArray as $company) {
        $criteria->params = array(':company' => $company);
        $companies[] = Company::model()->find($criteria);
    }
    return $companies;
}

この拡張機能では「値」プロパティが適切に実装されていないため、更新 します。この関数をモデルに拡張することについて言及しました。

    public function afterFind() {
       //tag is the attribute used in form
      $this->tag = $this->getAllTagNames();
      parent::afterFind();
   }
4

1 に答える 1

1

Issueとモデルの両方で定義された課題とタグの間にリレーションが必要ですTag( many_many リレーションである必要があります)。

したがって、モデルの問題にIssueControllerデータを送信するとcreateupdate関連するタグが取得されます (私の場合、「バグ、問題、...」などの文字列が取得されます)。次に、コントローラーでこの文字列を解析し、対応するモデルを取得して、関連するタグに割り当てる必要があります。

一般的な例を次に示します。

//In the controller's method where you add/update the record
$issue->tags = getRecordsFromAutocompleteString($_POST['autocompleteAttribute'], 'Tag', 'tag');

ここで私が呼んでいるメソッド:

//parse your string ang fetch the related models
public static function getRecordsFromAutocompleteString($string, $model, $field)
        {
            $string = trim($string);
            $stringArray = explode(", ", $string);
            $stringArray[count($stringArray) - 1] = str_replace(",", "", $stringArray[count($stringArray) - 1]);
            return CActiveRecord::model($model)->findAllByAttributes(array($field => $stringArray));
        }

$issue->tags は、関連するすべての Tags オブジェクトを含む配列です。

メソッドでは、次のafterSaveことができます。

protected function afterSave() {
    parent::afterSave();

    //$issue_id = Yii::app()->db->getLastInsertID(); Don't need it, yii is already doing it
    foreach ($this->tags as $tag) {
        $sql = "INSERT INTO issue_tag_map (issue_id_fk, tag_id_fk)VALUES(:issue_id,:tag_id)";     
        $command = Yii::app()->db->createCommand($sql);
        $command->bindValue(":issue_id", $this->id, PDO::PARAM_INT);
        $command->bindValue(":tag_id", $tag->id, PDO::PARAM_INT);
        $command->execute();
        }
}

上記のコードは基本的な解決策です。関連モデルを保存するには、activerecord-relation-behavior の拡張機能を使用することをお勧めします。この拡張機能を使用すると、afterSaveメソッドで何も定義する必要がなくなります。次のことを行うだけです。

$issue->tags = getRecordsFromAutocompleteString($_POST['autocompleteAttribute'], 'Tag', 'tag');
$issue->save(); // all the related models are saved by the extension, no afterSave defined!

次に、オートコンプリートでタグと一緒に ID をフェッチしてスクリプトを最適化し、選択した ID を Json 配列に保存できます。getRecordsFromAutocompleteStringこれにより、ID を取得するために SQL クエリを実行する必要がなくなります。上記の拡張機能を使用すると、次のことが可能になります。

$issue->tags = CJSON::Decode($_POST['idTags']);//will obtain array(1, 13, ...)
$issue->save(); // all the related models are saved by the extension, the extension is handling both models and array for the relation!

編集:

オートコンプリート フィールドに入力する場合は、次の関数を定義できます。

public static function appendModelstoString($models, $fieldName)
    {
        $list = array();
        foreach($models as $model)
        {
            $list[] = $model->$fieldName;
        }
        return implode(', ', $list);
    }

フィールドの名前 (あなたの場合はtag) と関連モデルのリストを指定すると、適切な文字列が生成されます。次に、文字列をビューに渡し、オートコンプリート フィールドのデフォルト値として配置します。

あなたの編集への答え:

コントローラーで、このモデルの会社は、オートコンプリート フォームから追加した会社であると言います。

$model->companies = $this->getRecordsFromAutocompleteString($_POST['News']  
   ['company']);

そのため、関連会社がフォームにない場合、関連モデルとして保存されません。2 つの解決策があります。

  1. 既存の関連モデルを表示する前にフォームのオートコンプリート フィールドに入れるたびに、関連モデルとして再度保存され、関連モデルから消えません。

    $this->widget('application.extensions.multicomplete.MultiComplete', array(
                    'name' => 'people',
                    'value' => (isset($people))?$people:'',
                    'sourceUrl' => array('searchAutocompletePeople'),
    ));
    
  2. を呼び出す前にコントローラーgetRecordsFromAutocompleteStringで、モデルの既存のモデルを追加します。

    $model->companies = array_merge(
        $model->companies, 
        $this->getRecordsFromAutocompleteString($_POST['News']['company'])
    );
    
于 2012-11-23T09:48:21.440 に答える