Yii2中通过API保存注册用户失败,如何解决非空约束错误?
问题描述
尝试通过API调用将注册用户保存到数据库时,触发数据库非空约束错误。调用http://localhost:8080/v1/user/signup接口并传入以下JSON:
{
"username": "example_user",
"password_hash": "example_password",
"email": "gmail@gmail.com"
}
报错信息如下:
{ "name": "Integrity constraint violation", "message": "SQLSTATE[23502]: Not null violation: 7 ERROR: null value in column \"username\" of relation \"user\" violates not-null constraint\nDETAIL: Failing row contains (3, null, null, null, null, null, 10, 1710925298, 1710925298, null).\nThe SQL being executed was: INSERT INTO \"user\" (\"status\", \"created_at\", \"updated_at\") VALUES (10, 1710925298, 1710925298) RETURNING \"id\"" }
相关代码及配置如下:
User.php 模型
<?php namespace app\models; use Yii; use yii\base\NotSupportedException; use yii\behaviors\TimestampBehavior; use yii\db\ActiveRecord; use yii\web\IdentityInterface; class User extends \yii\db\ActiveRecord implements IdentityInterface { const STATUS_DELETED = 0; const STATUS_INACTIVE = 9; const STATUS_ACTIVE = 10; public function behaviors() { return [ TimestampBehavior::class, ]; } public static function tableName() { return '{{%user}}'; } public function rules() { return [ ['status', 'default', 'value' => self::STATUS_ACTIVE], ['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_INACTIVE, self::STATUS_DELETED]], ]; } }
UserController.php 控制器
<?php // phpcs:ignoreFile namespace app\modules\v1\controllers; use Yii; use app\models\User; use yii\rest\ActiveController; use yii\web\Response; class UserController extends ActiveController { public $modelClass = 'app\models\User'; public function actionSignup() { $user = new User(); $user->load(Yii::$app->getRequest()->getBodyParams(), ''); if ($user->save()) { Yii::$app->response->statusCode = 201; return ['status' => 'success', 'data' => 'User registered successfully']; } else { Yii::$app->response->statusCode = 400; return ['status' => 'error', 'data' => $user->errors]; } } }
web.php 中的 urlManager 配置
'urlManager' => [ 'enablePrettyUrl' => true, 'showScriptName' => false, 'rules' => ['class' => 'yii\rest\UrlRule', 'controller' => 'v1/user', 'POST' => 'v1/user/signup'], ]
数据库表结构
$this->createTable('{{%user}}', [ 'id' => $this->primaryKey(), 'username' => $this->string()->notNull()->unique(), 'auth_key' => $this->string(32)->notNull(), 'verification_token'=>$this->string()->defaultValue(null), 'password_hash' => $this->string()->notNull(), 'password_reset_token' => $this->string()->unique(), 'email' => $this->string()->notNull()->unique(), 'status' => $this->smallInteger()->notNull()->defaultValue(10), 'created_at' => $this->integer()->notNull(), 'updated_at' => $this->integer()->notNull(), ]);
原因分析
- 模型缺少必填字段验证规则:User模型的
rules()方法仅定义了status字段的规则,没有包含username、email、password_hash等必填字段的验证,导致load()方法无法将请求参数赋值给模型属性。 auth_key字段未自动生成:数据库要求auth_key为非空字段,但模型中没有处理该字段的自动生成逻辑,保存时该字段为null,触发约束错误。- URL规则配置不规范:原URL规则可能导致请求映射异常,影响参数解析。
解决步骤
1. 完善User模型的验证规则
在rules()方法中添加必填字段的验证规则,确保请求参数能被正确赋值和验证:
public function rules() { return [ ['status', 'default', 'value' => self::STATUS_ACTIVE], ['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_INACTIVE, self::STATUS_DELETED]], // 添加必填字段验证与格式规则 [['username', 'email', 'password_hash'], 'required'], [['username', 'email'], 'string', 'max' => 255], [['username', 'email'], 'unique'], ]; }
2. 自动生成auth_key字段
在User模型中重写beforeSave()方法,在插入新用户时自动生成随机的auth_key:
public function beforeSave($insert) { if (parent::beforeSave($insert)) { if ($insert) { // 生成32位随机字符串作为auth_key $this->auth_key = Yii::$app->security->generateRandomString(); } return true; } return false; }
3. 调整URL规则配置
修改urlManager的规则,确保POST请求正确映射到signup动作:
'urlManager' => [ 'enablePrettyUrl' => true, 'showScriptName' => false, 'rules' => [ 'POST v1/user/signup' => 'v1/user/signup', ['class' => 'yii\rest\UrlRule', 'controller' => 'v1/user'], ], ]
4. 优化控制器参数处理(可选)
可以在保存前显式调用validate()方法,提前获取验证错误(save()方法会自动调用validate(),此步骤为可选):
public function actionSignup() { $user = new User(); $user->load(Yii::$app->getRequest()->getBodyParams(), ''); if ($user->validate() && $user->save()) { Yii::$app->response->statusCode = 201; return ['status' => 'success', 'data' => 'User registered successfully']; } else { Yii::$app->response->statusCode = 400; return ['status' => 'error', 'data' => $user->errors]; } }
完成以上修改后,重新调用接口即可正常保存用户数据。
内容的提问来源于stack exchange,提问作者mightycode Newton
相关产品推荐
相关产品推荐

