我有一个带有文件上传字段的表单,我已经创建了一个模型行为文件来处理文件处理。
我有两个函数,beforeSave和afterSave:
在beforeSave中我做了一些事情,然后将数据中的文件值设置为null,以便保存。否则它将尝试保存数组,数据库只需要一个字符串(文件名)
在afterSave中,我根据表单上的一些文本字段生成一个新文件名,并在其前面添加lastInsertId。我还将文件从temp移动到所需位置。 这一切都运行正常,但是当我尝试将新文件名保存到模型时它只是不起作用。
我做了很多测试和调试,也花了数小时在线搜索。结论是你无法保存在afterSave之后,它会自动触发并在之前再次运行。
所以我的问题是,如何更新新插入的模型?插入的文件名需要在其名称中包含主键,并在beforeSave时具有未知。
感谢任何帮助! 杰森
答案 0 :(得分:15)
如果你想在afterSave()本身绕过所有回调(afterSave / beforeSave),我发现这个语法对我有用:
$this->save($data, array('callbacks'=>false));
要禁用触发器,手册会说明:
save方法也有另一种语法:
save(array $ data = null,array $ params = array()) $ params数组可以具有以下任何可用选项作为键:
array(
'validate' => true,
'fieldList' => array(),
'callbacks' => true //other possible values are false, 'before', 'after' )
答案 1 :(得分:6)
可以这样做
// Its your model Image.php
function afterSave($created) {
if($created) {
// its new record
// do your work here
}
}
小调整(不推荐)
如果你想在afterSave()中使用$this->Model->query()
而不是$this->Model->save()
而不是// little hack to bypass beforeSave
$this->Model->query('UPDATE listings SET name="xx" WHERE id="1"');
来绕过beforeSave on db操作;
{{1}}
答案 2 :(得分:0)
就个人而言,保存模型后,所有文件处理都应在控制器(或组件)中完成。我不认为模型应该根据MVC设计来管理文件。
在您的控制器
中// Save model
if ($model->save()) {
// Save your file
...
// Update the model
$model->updateField();
}
$model->save();
希望得到这个帮助。
答案 3 :(得分:0)
理想情况下,如果您的文件名依赖于数据库中的其他列,则无需再次重新保存模型数据。实际上,它会在表的模式中引入彼此依赖的列,这违反了规范化。
EG。如果您的文件名格式为“textfield1-textfield2-yourid.ext”,则应将textfield1
,textfield2
和ext
的值存储在数据库中。然后,在模型的afterFind()
方法中,您可以遍历结果,将生成的文件名创建为数据数组中的新字段。
样本表架构:
id | textfield1 | textfield2 | extension | created | modified
示例查看代码:
echo $this->Html->image("{$data['Picture']['textfield1']}-{$data['Picture']['textfield2']}-{$data['Picture']['id']}.{$data['Picture']['extension']}");
当然,正如我之前提到的,如果你覆盖模型中的afterFind()并创建一个名为“filename”的新字段,这可以简化。关于here的更多内容。
这会将您的代码缩短为:
echo $this->Html->image($data['Picture']['filename']);
并且还可以在任何时候更容易地进行普遍修改。