我们以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', ]]这种数据,也就是说,在页面表单中有如同下面的代码:
<form action="save.php" method="POST"> <input type="text" name="User[username]" value=""> <input type="password" name="User[password]" value=""> <button type="submit">保存</button> </form>这种方式特别适合后台的编辑和保存,因为后台编辑保存数据往往比较单一,大多数针对同一个数据表。 但是,如果是用户注册、用户登记信息、提交订单等场景,就不那么好使了。因为后台要根据数据进行重组。 当然,如果整理好数据,也是可以做到的,但你必须删除掉该数组内不属于数据表字段的键名。 但是万一表单提交过来的数据如果太少了怎么办?比如User表还有用户昵称字段nick必须提供,但是你还是希望保存用户提交过来的数据(即兼容保存,很多时候业务会在JS层做好用户必填字段的限制,但是后台就放宽松了很多,尤其是大表单)。 没关系,还是有办法的,我们可以利用Yii2.0自带的数据库操作: 参考:http://www.yiichina.com/doc/guide/2.0/db-active-record#
这种方式是可以成功保存数据的,但是一定要保证nick有默认值比如空字符串,或者关闭MySQL的严格模式:
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
但是如果字段数太多了,比如30多个,难道要写30多行代码吗(核对30个字段名有没有写对,真是崩溃)?如果数据表字段有增减,岂不是很麻烦?
没关系,我们还有办法:
所以: 这里就要提到load方法的一个缺点了,它依赖于User.php这个Model的rules,如果rules里忘记增加某个字段的规则定义,无论定义其为required还是string数据类型,哪怕出现一个,也可以顺利load上值,如果一个都没有,比如username在rules里没出现,那么load以后,$user->username的值为NULL。所以,我们无论何时何地,一定要确保rules里对字段有齐全的定义。 但是:如果某个数据表可以给用户自定义字段呢?用户通过网页操作,给这个表增加字段后,我们总不能让用户生成一个Model吧?这时候,就必须用方法三。我们可以将那个setAllAttributes方法放到一个基类比如里面,让这个基类继承\yii\db\ActiveRecord,让我们所有通过gii创建的Model类继承这个Model(反正有命名空间):
<?php 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())); }