Yii CJuiAutoComplete用于多个值

Yii CJuiAutoComplete用于多个值,autocomplete,yii,yii-extensions,Autocomplete,Yii,Yii Extensions,我是一名Yii初学者,目前正在开发一个标签系统,其中有3个表格: 问题(id、内容、创建等) 标签(id,标签) 问题标记地图(id,标记id,问题id) 在我的/Views/Issue/_表单中添加了一个扩展来检索多个标签ID和标签 我使用了afterSave功能,以便直接将Issue\u id和自动完成的Tag\u ids存储在Issue\u Tag\u map表中,其中具有许多关系 不幸的是,没有归还任何东西 我想知道是否有办法将自动完成的标记ID存储在临时属性中,然后将其传递给模型的

我是一名Yii初学者,目前正在开发一个标签系统,其中有3个表格:

  • 问题(id、内容、创建等)

  • 标签(id,标签)

  • 问题标记地图(id,标记id,问题id)

在我的
/Views/Issue/_表单中
添加了一个扩展来检索多个标签ID和标签

我使用了
afterSave
功能,以便直接将
Issue\u id
和自动完成的
Tag\u id
s存储在
Issue\u Tag\u map
表中,其中
具有许多关系

不幸的是,没有归还任何东西

我想知道是否有办法将自动完成的标记ID存储在临时属性中,然后将其传递给模型的
afterSave(
)函数

我已经搜索了一段时间,这让我发疯,因为我觉得我错过了一个非常简单的步骤

我们非常感谢您的任何帮助或建议

视图/问题/_形式多完成

这是问题模型中用于填充标记的自动完成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>
更新 由于“值”属性在该扩展中未正确实现,我提到将此函数扩展到模型:

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

Issue
Tag
模型中定义的Issue和Tag之间应该有一个关系(应该是多个关系)

因此,在
IssueController
中,当您将数据发送到
create
update
模型问题时,您将得到相关的标记(在我的例子中,我得到一个类似“bug,problem,…”的字符串)。 然后,您需要在控制器中解析这个字符串,获取相应的模型并将它们分配给相关的标记

以下是一个通用示例:

//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();
        }
}
$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!
现在,上面的代码是一个基本的解决方案。我鼓励您使用以保存相关模型。 使用此扩展,您不必在
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数组中。这样,您就不必执行sql查询
getRecordsFromAutoCompleteTString
来获取ID。通过上述扩展,您将能够执行以下操作:

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();
        }
}
$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!
编辑:

如果要填充“自动完成”字段,可以定义以下函数:

    $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 static function appendModelstoString($models, $fieldName)
    {
        $list = array();
        foreach($models as $model)
        {
            $list[] = $model->$fieldName;
        }
        return implode(', ', $list);
    }
您给出了字段的名称(在您的例子中是
标记
)和相关模型的列表,它将生成相应的字符串。然后将字符串传递给视图,并将其作为自动完成字段的默认值

回答您的编辑:

在控制器中,您表示此模型的公司是您从自动完成表单中添加的公司:

$model->companies = $this->getRecordsFromAutocompleteString($_POST['News']  
   ['company']);
因此,如果关联公司不在表单中,它将不会保存为关联模型。 您有两种解决方案:

  • 每次将已存在的相关模型放入表单的“自动完成”字段,然后再将其显示,这样它们将再次保存为相关模型,并且不会从相关模型中禁用

    $this->widget('application.extensions.multicomplete.MultiComplete', array(
                    'name' => 'people',
                    'value' => (isset($people))?$people:'',
                    'sourceUrl' => array('searchAutocompletePeople'),
    ));
    
  • 在调用
    GetRecordsFromAutoCompleteTring
    之前,在控制器中添加模型的现有模型

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

  • 在回答之前,只需回答两个小问题:自动完成正在工作,对吗?您是否在模型中定义了问题和标记之间的关系?(我需要这些信息使我的回答更准确)非常感谢你的回复!我目前已经创建了这个关系:'tags'=>array(self::MANY\u MANY,'Tag','issue\u Tag\u map(Tag\u id\u fk,issue\u id\u fk),我现在面临的唯一问题是将属性从模型传递到自动完成函数。因为现在自动完成功能不起作用,或者您希望在提交表单后获得结果?我在为自动完成字段分配临时属性时遇到问题。另外,当我为测试分配临时属性时,例如:getRecordsFromAutoc完整字符串($\u POST['isseuetempattrib'],'Tag','Tag'),它要么在控件中没有标识,要么属性在模型中返回null!!我正在考虑使用复选框列表而不是自动完成,并将这两个模型结合在一起:Issue和Issue_tag_映射在一个表单中我已经安装了activerecord关系行为的扩展,现在我可以明确地理解这是多么简单!我已经添加了多个关系,在updatecreate函数中我添加了:$mode->tags=(必须存储的标记数组)不幸的是,我仍在试图找出如何从_表单传递标记数组,因为我不知道初始化或使用哪个属性!一般来说,我所做的是自动完成源url返回一个带有标记id和标记的数组。然后在javascript中,当用户选择标记时(自动完成小部件中的“选择”事件)我将id添加到一个隐藏字段中,该字段包含所有选定id的json数组({1,3,5,6,…}),当我收到POST请求时,我将隐藏字段解码到您为记录指定的php数组中(例如:$mode->tags=CJson::decode($POST['the_hidden_field']))