我正在制作一个用户注册表,其中涉及 3 个不同的对象:用户、成员个人资料和成员组织。我试图将所有这些嵌入到一个注册表中,例如“用户”>“会员”>“学校”。这个的基本实现与典型的
sfDoctrineForm::embedRealtion
程序配合得很好。
问题是组织在其
member_number
上有一个唯一的索引,唯一提供的值不会出现在数据库中的是当该用户是第一个从其组织注册的人时。因此,在这种情况下,我们将收到一个 vlaidation 错误(或者如果我们关闭验证,则会出现关键约束违规)。
我想要发生的是,我检查数据库中是否存在具有相同
member_number
的 MemberOrganization(在前/后验证器中或在 updateObject 中或在任何适当的地方)。如果会员编号已经存在,那么我想将新的 MemberProfile 与此现有组织相关联,而不是将其链接到提交的新组织,从而丢弃该组织的所有新值。
我尝试通过验证修改组织表单中的对象,但这总是会导致来自配置文件的
organization_id
约束违规:
$object = $this->getObject();
$table = $object->getTable();
$existing = $table->findOneByMemberNumber($values['member_number']);
if($existing)
{
$members = clone $object->Members;
$object->assignIdentifier($existing->identifier());
$object->fromArray($existing->toArray(false), false);
foreach($members as $member)
{
$member->link($object);
}
$values = $object->toArray(false); // return only the direct values
}
return $values;
架构看起来像这样:
User:
columns:
username: {type: string(100)}
email: {type: string(255), unique: true}
MemberProfile:
columns:
# some none authentication related user details
organization_id: {type: integer, notull: true}
user_id: {type: integer, notnull: true}
relations:
User:
local: user_id
type: one
foreign: id
foreignType: one
MemberOrganization:
local: orgainization_id
type: one
foreign: id
foreignType: many
foreignAlias: Members
MemberOrganization:
columns:
membership_number: {type: string(255), unique: true}
# other organization data
所以我最终做的是覆盖顶级表单(用户的表单)上的
bind
。在此方法中,我检查组织是否存在,如果存在,我将其附加到成员配置文件对象,然后重新嵌入所有子表单。
理想情况下,我实际上会在成员表单中执行此操作,但由于这些值仅绑定在顶级表单中,然后只是级联错误模式进行验证,这似乎是行不通的。似乎需要完全重新嵌入才能使对象关联正确。
一些示例代码(在发出查询之前减去会员号码上的一些清理代码):
public function linkOrganizationIfExists(array $orgValues)
{
$defaultOrg = $this->embeddedForms['member_profile']->embeddedForms['organization']->getObject();
$table = $defaultOrg->getTable();
if(isset($orgValues['member_number'])
&& ($existingOrg = $table->findOneByMemberNumber($orgValues['member_number'])))
{
$user = $this->getObject();
$profile = $user->getMemberProfile();
$profile->Organization = $existingOrg;
// prepare the current values from the db to return
$orgValues = array_merge($orgValues, array_intersect_key($existingOrg->toArray(false), $orgValues));
$this->embedRelation('MemberProfile as member_profile', 'MemberProfileRegisttrationForm');
}
return $orgValues;
}
public function bind(array $taintedValues = null, array $taintedFiles = null)
{
if(isset($taintedValues['member_profile']['organization']))
{
$taintedValues['member_profile']['organization'] = $this->linkOrganizationIfExists($taintedValues['member_profile']['organization']);
}
parent::bind($taintedValues, $taintedFiles);
}