cakephp3:保存关联数据

问题描述 投票:0回答:1

我想为 cakephp3 应用程序编写一个简单的标记插件。假设我们有一个模型 books 和一个模型 reviews。对于每个模型,应该可以附加标签 - 只需添加一个行为(在插件中):

$this->addBehavior('Tag.Taggable')

我在数据库中创建了两个表:

tags, tagged_tags

表 tagged_tags:

id  |  tag_id  |  tagged_id                   |
1   |  1       |  1                           |
2   |  2       |  1                           |

tagged_id 是标记实体的 id。它属于哪个型号的信息在另一个表中。 表格标签:

id  |  tag     |  model                       |
1   |  book    |  App\Model\Table\BooksTable  |
2   |  nobook  |  App\Model\Table\ReviewsTable|

显然,只有第一个标签属于一本书。

class TaggableBehavior extends Behavior
{
    // Some more code here

    public function __construct(Table $table, array $config = [])
    {
        parent::__construct($table, $config);
        $this->_table = $table;

        $this->_table->belongsToMany('Tag.Tags', [ 
            'joinTable' => 'tagged_tags',
            'foreignKey' => 'tagged_id',
            'targetForeignKey' => 'tag_id',
            'conditions' => [
                'Tags.model' => get_class($this->_table);
            ]
        ]);

    }
}

检索数据工作完美。但节省是一个问题:

错误:SQLSTATE[42S22]:未找到列:1054 未知列 “where 子句”中的“Tags.model”

SQL查询:

选择 TaggedTags.id AS

TaggedTags__id
,TaggedTags.tagged_id AS
TaggedTags__tagged_id
,TaggedTags.tag_id AS
TaggedTags__tag_id
来自 tagged_tags TaggedTags WHERE (tagged_id = :c0 AND Tags.model = :c1)

我不太确定为什么 cakephp 在这里执行 SELECT 查询,我也不在乎。为什么这个查询会导致错误是很清楚的。但我的错误在哪里呢?这与

'conditions' => ['Tags.model' => get_class($this->_table);
有关。没有这个,我可以保存数据(但不能说哪个标签属于一本书或不属于一本书)

编辑:一些附加信息

这里是完整的sql语句,显示在调试工具包中http://freetexthost.com/tc3s46nugi

控制器代码:

public function add()
{
    $book = $this->Books->newEntity();
    if ($this->request->is('post')) {
        $book = $this->Books->patchEntity($book, $this->request->data);
        if ($this->Books->save($book)) {
            $this->Flash->success(__('The book has been saved.'));
            return $this->redirect(['action' => 'index']);
        } else {
            $this->Flash->error(__('The book could not be saved. Please, try again.'));
        }
    }

在行为中,我有一些来自书签教程的逻辑(复制/粘贴)

public function beforeSave($event, $entity, $options)
{
    if ($entity->tag_string) {
        $entity->tags = $this->_buildTags($entity->tag_string);
    }
}

protected function _buildTags($tagString)
{
    $new = array_unique(array_map('trim', explode(',', $tagString)));
    $out = [];
    $query = $this->_table->Tags->find()
        ->where([
            'Tags.tag IN' => $new,
            'Tags.model' => $this->name()
            ]);
    // Remove existing tags from the list of new tags.
    foreach ($query->extract('tag') as $existing) {
        $index = array_search($existing, $new);
        if ($index !== false) {
            unset($new[$index]);
        }
    }
    // Add existing tags.
    foreach ($query as $tag) {
        $tag['count'] = $tag['count']+1;
        $out[] = $tag;
    }
    // Add new tags.
    foreach ($new as $tag) {
        $out[] = $this->_table->Tags->newEntity(['tag' => $tag, 'model' => $this->name(), 'count' => 0]);
    }
    return $out;
}
php conditional-statements associations cakephp-3.0
1个回答
0
投票

如果您创建标签模型,并创建与其他模型的 HABTM 关系,您将制作简单的标记插件。

这里有简单的指南。

添加.ctp

省略多个选择标签字段,而是放置标签文本字段(例如tagsinput)。添加一些 jquery 标记插件。添加新标签(关键字)时,它会立即通过 jquery post 方法存储在标签表中。如果标签表中存在该关键字,则不要再次存储。

行为

在 beforeSave 方法中处理来自标记字段的值。 如果值用逗号分隔,您可以使用类似这样的内容 (CakePHP 2):

public function beforeSave($options = array())
    {
        if(!empty($this->data['Article']['tagsinput'])) {
            $tags = explode(',', $this->data['Article']['tagsinput']);
            foreach ($tags as $tag) {
                $tagKey = $this->Tag->find('first',array(
                    'recursive' => -1,
                    'fields' => array('id'),
                    'conditions' => array('Tag.name' => $tag)
                    ));
                $this->data['Tag']['Tag'][] = $tagKey['Tag']['id'];
            }
        }
        return true;
    }

这将创建 HABTM 关系并将这些值存储在表articles_tags中。

编辑.ctp

创建逗号分隔值:

<?php
            $extract_tags = Hash::extract($this->data['Tag'],'{n}.name');
            $tags = implode(',', $extract_tags);
            echo $this->Form->input('tagsinput',
                array(
                    'id' => 'tags',
                    'div'=>true,
                    'label'=>__('Tags'),
                    'class'=>'form-control input-lg',
                    'placeholder'=>__('Add keywords here'),
                    'value' => $tags
                    )
                );
            ?>
© www.soinside.com 2019 - 2024. All rights reserved.