我们以User表为例,假设User表就3个字段,id, username, password。
当PHP从浏览器接收POST数据后,Yii提供了一种推荐的如下方式:
首先要new User;
load方法的源码在:vendor/yiisoft/yii2/base/Model.php,786行左右(根据版本可能有差异),定义如下:
public function load( data, formName = null)
第一个参数 data是如同User:username:′admin′,paafssword:′adminPassword′,第二个参数如果不传递,那么必须保证 data中有以new User的User这个类相同的键,即“User”。
如果传递,则传递在 data中含有插入数据的键,即Uer。在这里我强烈建议传入第二个参数,以显示告诉读者在 data中的有效数据在User这个键下面。另一方面,如果某一天new User改为new UserModel,我们不需要修改其它代码。
data一般来源于POST数据比如 _POST,yii中我们习惯用Yii::$app->request->post()。
而为什么一定要将给User表的数据存储到一个User的键下面呢?这是为了在一个页面提交过来的数据可以提供给多个表存储使用,比如可以从页面中传输user表和user_profile表存储的数据。
那么,当我们一个页面只管理一个表的时候,完全可以用这种方式。当然,在Yii框架中,如果开启了CSRF防跨站攻击,POST到php后台的数据就带有_csrf键,如果YII_DEBUG常量设置为TRUE了,网页会抛出异常的!所以,多一事不如少一事,yii框架就让我们坚决用”表名[字段名]”的方式给input做name吧。
$user = new User();
$data = Yii::$app->request->post();
if (!$user->load($data, 'User')) {
$this->showErrorPage('提供的数据格式不正确!');
}
if (!$user->save()) {
$this->showErrorPage(current($user->getFirstErrors()));
}
这种方式接收表单数据存储到数据库时,表单数据是如同:
['User' => [
'username' => 'admin',
'password' => 'admin',
]]
这种数据,也就是说,在页面表单中有如同下面的代码:
这种方式特别适合后台的编辑和保存,因为后台编辑保存数据往往比较单一,大多数针对同一个数据表。
但是,如果是用户注册、用户登记信息、提交订单等场景,就不那么好使了。因为后台要根据数据进行重组。
当然,如果整理好数据,也是可以做到的,但你必须删除掉该数组内不属于数据表字段的键名。
但是万一表单提交过来的数据如果太少了怎么办?比如User表还有用户昵称字段nick必须提供,但是你还是希望保存用户提交过来的数据(即兼容保存,很多时候业务会在JS层做好用户必填字段的限制,但是后台就放宽松了很多,尤其是大表单)。
没关系,还是有办法的,我们可以利用Yii2.0自带的数据库操作:
参考:http://www.yiichina.com/doc/guide/2.0/db-active-record#
$user = new User();
$user->username = @$_POST['username'];
$user->password= @$_POST['password'];
if ($user->save()) {
...
}
这种方式是可以成功保存数据的,但是一定要保证nick有默认值比如空字符串,或者关闭MySQL的严格模式:
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
去掉STRICT_TRANS_TABLES,即可成功保存而不报错误。
但是如果字段数太多了,比如30多个,难道要写30多行代码吗(核对30个字段名有没有写对,真是崩溃)?如果数据表字段有增减,岂不是很麻烦?
没关系,我们还有办法:
$user = new User();
$data = Yii::$app->request->post();
$user->seAttributes($data['User'], false));
if (!$user->save()) {
$this->showErrorPage(current($user->getFirstErrors()));
}
所以:
这里就要提到load方法的一个缺点了,它依赖于User.php这个Model的rules,如果rules里忘记增加某个字段的规则定义,无论定义其为required还是string数据类型,哪怕出现一个,也可以顺利load上值,如果一个都没有,比如username在rules里没出现,那么load以后,$user->username的值为NULL。所以,我们无论何时何地,一定要确保rules里对字段有齐全的定义。
但是:如果某个数据表可以给用户自定义字段呢?用户通过网页操作,给这个表增加字段后,我们总不能让用户生成一个Model吧?这时候,就必须用方法三。我们可以将那个setAllAttributes方法放到一个基类比如里面,让这个基类继承\yii\db\ActiveRecord,让我们所有通过gii创建的Model类继承这个Model(反正有命名空间):
namespace common\models;
class Model extends \yii\db\ActiveRecord {
function loadData($data, $key) {
$data = $key ? @$data[$key] : $data;
if (!is_array($data)) {
return false;
}
$this->setAttributes($data, false);
return true;
}
}
用法还是那样,只不过这次不依赖rules了:
$user = new User(); $data = Yii::$app->request->post(); if (!$user->loadData($data, 'User')) { $this->showErrorPage('提供的数据格式不正确!'); } if (!$user->save()) { $this->showErrorPage(current($user->getFirstErrors())); }