我目前正在努力完成从 CakePHP 3.3 到 4.4 的升级。我现在在几个地方遇到了同样的问题,都是相同的 SQLSTATE 错误:
SQLSTATE[HY000]: General error: 1364 Field 'cert_request' doesn't have a default value
代码目前如下所示:
$cert = $this->Certs->newEmptyEntity();
$data = $this->request->getData();
if(array_key_exists('certificate', $data) && !is_null($data['certificate'])) {
$certificate = $data['certificate'];
$cert_string = $certificate;
$certificated = openssl_x509_parse($certificate);
} else {
if ($this->request->is('post')) {
$data['effective_date'] = date('Y-m-d H:i', strtotime($data['effective_date']));
$data['expiry_date'] = date('Y-m-d H:i', strtotime($data['expiry_date']));
$cert = $this->Certs->patchEntity($cert, $data);
// Database Error happens here during save()
if ($this->Certs->save($cert)) {
$this->Flash->success(__('The cert has been saved.'));
return $this->redirect(['action' => 'index']);
} else {
$this->Flash->error(__('The cert could not be saved. Please, try again.'));
}
}
}
请注意,
$data
确实不包含“cert_request”和与此问题相关的其他字段。
namespace App\Model\Table;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;
/**
* Certs Model
*
* @property \Cake\ORM\Association\BelongsTo $Requests
* @property \Cake\ORM\Association\BelongsTo $CertTemplates
* @property \Cake\ORM\Association\BelongsTo $CertStatuses
* @property \Cake\ORM\Association\BelongsTo $Users
*
* @mixin \Cake\ORM\Behavior\TimestampBehavior
*/
class CertsTable extends Table
{
public function initialize(array $config): void
{
parent::initialize($config);
$this->setTable('certs');
$this->setDisplayField('id');
$this->setPrimaryKey('id');
$this->addBehavior('Timestamp');
$this->belongsTo('CertTemplates', [
'foreignKey' => 'cert_template_id',
'joinType' => 'INNER'
]);
$this->belongsTo('CertStatuses', [
'foreignKey' => 'cert_status_id',
'joinType' => 'INNER'
]);
$this->belongsTo('Users', [
'foreignKey' => 'user_id'
]);
$this->hasMany('CertAlerts', [
'foreignKey' => 'cert_id'
]);
}
public function validationDefault(Validator $validator): \Cake\Validation\Validator
{
$validator
->integer('id')
->allowEmptyFor('id', Validator::EMPTY_ALL, Validator::WHEN_CREATE)
->add('id', 'unique', ['rule' => 'validateUnique', 'provider' => 'table']);
$validator
->dateTime('revocation_date')
->allowEmptyDatetime('revocation_date');
$validator
->dateTime('effective_revocation_date')
->allowEmptyDatetime('effective_revocation_date');
$validator
->allowEmptyString('revocation_reason');
$validator
->requirePresence('common_name', 'create')
->notEmptyString('common_name');
$validator
->requirePresence('cert_template_id', 'create')
->notEmptyString('cert_template_id');
$validator
->requirePresence('requester_name', 'create')
->notEmptyString('requester_name');
$validator
->requirePresence('requester_email', 'create')
->notEmptyString('requester_email');
$validator
->allowEmptyString('budget_zi');
$validator
->allowEmptyString('billable');
$validator
->allowEmptyString('key_csr');
$validator
->allowEmptyString('cert_request');
$validator
->allowEmptyString('subject');
$validator
->allowEmptyString('alternative_name');
$validator
->allowEmptyString('serial_no');
$validator
->allowEmptyString('cert');
$validator
->allowEmptyString('ticket');
$validator
->dateTime('request_submission_date')
->allowEmptyDatetime('request_submission_date');
$validator
->dateTime('effective_date')
->requirePresence('effective_date', 'create')
->notEmptyDatetime('effective_date');
$validator
->dateTime('expiry_date')
->requirePresence('expiry_date', 'create')
->notEmptyDatetime('expiry_date');
$validator
->requirePresence('country', 'create')
->notEmptyString('country');
$validator
->requirePresence('organization', 'create')
->notEmptyString('organization');
$validator
->requirePresence('organization_unit', 'create')
->notEmptyString('organization_unit');
$validator
->requirePresence('city', 'create')
->notEmptyString('city');
$validator
->requirePresence('state', 'create')
->notEmptyString('state');
$validator
->allowEmptyString('issued_email');
$validator
->allowEmptyString('san');
$validator
->allowEmptyString('remarks');
return $validator;
}
public function buildRules(RulesChecker $rules): \Cake\ORM\RulesChecker
{
$rules->add($rules->isUnique(['id']));
$rules->add($rules->existsIn(['cert_template_id'], 'CertTemplates'));
$rules->add($rules->existsIn(['cert_status_id'], 'CertStatuses'));
$rules->add($rules->existsIn(['user_id'], 'Users'));
$rules->add($rules->existsIn(['cert_id'], 'CertAlerts'));
return $rules;
}
}
现在我确实添加了以下代码来解决问题,但感觉更像是一个黑客而不是实际的解决方案
if (!array_key_exists('cert_request', $data)) { $data['cert_request'] = ''; }
if (!array_key_exists('ip_address', $data)) { $data['ip_address'] = ''; }
现在这些字段在数据库中确实没有默认值,但我认为在当前产品版本(PHP 5.4 和 CakePHP 3.3)中,它只是在值不存在时添加空字符串。
我一直在阅读迁移说明,但没有找到可以解释为什么这种行为发生变化或者工作方式不同的内容。
有些部分很难调试(该应用程序是在产品上开发的,依赖于本地无法使用的外部身份验证),这就是为什么我可能错过了一些东西。老实说,任何知道问题可能是什么都会有帮助。
我感受到你的痛苦。我遇到了类似的问题,因为 mysql 自动将这些值转换为空字符串,而 mariadb 抛出了错误。
我认为您应该始终在数据库表中保留默认值,如果您不确定在保存新数据库记录时是否始终设置它们。
您还可以在表模型中的“beforeSave”回调中添加设置空值的逻辑 但是 在我看来,在数据库级别解决这个问题是更干净的解决方案。