sfDoctrineForm - Как я могу проверить, существует ли объект во встроенной форме, и связать его с новым родительским объектом вместо создания нового? - PullRequest
0 голосов
/ 09 марта 2011

Я работаю над формой регистрации пользователя, которая включает в себя 3 различных объекта: пользователя, профиль участника и организацию участника.Я пытаюсь встроить все это в одну регистрационную форму, как Пользователь> Пользователь> Школа.Базовая реализация этого прекрасно работает с типичной процедурой sfDoctrineForm::embedRealtion.

Проблема в том, что организация имеет уникальный индекс на member_number, единственный раз, когда предоставленное значение для этого не будет вбаза данных - это когда пользователь первым регистрируется в своей организации.Так что в этом случае мы получим ошибку проверки (или нарушение ключевого ограничения, если мы отключим проверку).

Вместо этого я хочу, чтобы я проверил существование MemberOrganization с тем жеmember_number в базе данных (либо в валидаторе pre / post, либо в 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

1 Ответ

0 голосов
/ 12 марта 2011

Итак, в итоге я переопределил 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);
  } 
...