我是Yii初学者,我目前正在开发一个Tagging系统,我有3个表:
问题(id,content,create_d,...等)
标签(id,标签)
Issue_tag_map(id,tag_id_fk,issue_id_fk)
在我的/Views/Issue/_form
我添加了MultiComplete扩展程序以检索多个标记ID和标签,
我使用afterSave
函数直接将Issue_id
和自动完成的Tag_id
存储在Issue_tag_map
表中,其中HAS_MANY
为afterSave(
关系。
很遗憾没有回复。
我想知道是否有办法将自动完成的Tag_ids存储在临时属性中,然后将其传递给模型的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');
?>
中的MultiComplete:
/model/Issue
After 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();
}
}
:
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));
这是填充标记的问题模型中的自动完成sourceUrl:
// 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();
}
}
/ controllers / IssueController中的actionTagAutoComplete:
<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();
}
更新 因为&#34;值&#34; porperty在此扩展中没有正确实现我提到将此函数扩展到模型:
{{1}}
答案 0 :(得分:2)
您应该在Issue
和Tag
模型中定义的问题和标签之间存在关联(应该是一个多人关系)。
所以当IssueController
将数据发送到create
或update
模型问题时,您将获得相关标签(在我的情况下,我会得到一个类似'bug的字符串,问题,...')。
然后,您需要在控制器中解析此字符串,获取相应的模型并将它们分配给相关的标记。
这是一个通用的例子:
//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-&gt;标签是一个包含所有相关标签对象的数组。
在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's extension保存相关模型。
使用此扩展程序,您无需在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查询getRecordsFromAutocompleteString
来获取ID。通过上面提到的扩展,您将能够:
$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']);
因此,如果相关公司不在表格中,则不会将其保存为相关模型。 你有两个解决方案:
每次在显示之前将已存在的相关模型放在表单中的自动填充字段中,这样它们将再次保存为相关模型,并且不会从相关模型中消失
$this->widget('application.extensions.multicomplete.MultiComplete', array(
'name' => 'people',
'value' => (isset($people))?$people:'',
'sourceUrl' => array('searchAutocompletePeople'),
));
在调用getRecordsFromAutocompleteString
之前,在控制器中添加模型的现有模型。
$model->companies = array_merge(
$model->companies,
$this->getRecordsFromAutocompleteString($_POST['News']['company'])
);