Symfony生成表单、Doctrine和M:N关系

3
我有一个基本的M:N设置,包括三个表:candidate,position和candidate_position。以下是我尝试用文本形式描述的crow's-foot风格ERD的最佳版本。
可能是重复的:
Symfony Generator Forms, Doctrine和M:N关系
[candiate]-||------|<[candidate_position]>|------||-[position]

我想要实现的是:当创建或编辑一个候选人时,表单将包括一个复选框数组,用于分配给该候选人的所有可用职位。
在Web应用程序开发的正常世界中,这真的非常容易。但我正在尝试提高自己使用Symfony的管理生成器的能力。以下是我目前的进展。

apps/backend/modules/condidate/config/generator.yml

generator:
  class: sfDoctrineGenerator
  param:
    model_class:           Candidate
    theme:                 admin
    non_verbose_templates: true
    with_show:             false
    singular:              ~
    plural:                ~
    route_prefix:          candidate
    with_doctrine_route:   true
    actions_base_class:    sfActions

    config:
      actions: ~
      fields:  
    first_name: { label: First Name }
    last_name:  { label: Last Name }
    created_at: { label: Created On }
    positions:  {}
      list:    
    sort:  [last_name, asc]
      filter:  ~
      form:    
    display:
      "User": [first_name, last_name]
      "Applying For": [positions]
    fields :
      hide:  [created_at]
      edit:    ~
      new:     ~

lib/form/doctrine/candidateForm.class.php

class candidateForm extends BasecandidateForm
{
  public function configure()
  {
    unset( $this['created_at'] );

    $this->widgetSchema['positions'] = new sfWidgetFormDoctrineChoice(
      array( 'multiple' => true, 'model' => 'Position', 'renderer_class' => 'sfWidgetFormSelectCheckbox' )
    );

    $this->validatorSchema['positions'] = new sfValidatorDoctrineChoice(
      array( 'multiple' => true, 'model' => 'Position', 'min' => 1 )
    );
  }
}

config/doctrine/schema.yml

candidate:
  columns:
    id:
      type: integer(4)
      primary: true
      unsigned: true
      notnull: true
      autoincrement: true
    first_name:
      type: string(45)
      notnull: true
    last_name:
      type: string(45)
      notnull: true
    created_at:
      type: integer(4)
      unsigned: true

position:
  columns:
    id:
      type: integer(4)
      primary: true
      unsigned: true
      notnull: true
      autoincrement: true
    name:
      type: string(45)

candidatePosition:
  tableName: candidate_position
  columns:
    candidate_id:
      type: integer(4)
      primary: true
      unsigned: true
      notnull: true
    position_id:
      type: integer(4)
      primary: true
      unsigned: true
      notnull: true
  relations:
    candidate:
      class: candidate
      local: candidate_id
      foreign: id
      foreignAlias: candidate_positions
    position:
      class: position
      local: position_id
      foreign: id
      foreignAlias: candidate_positions
  indexes:
    fk_candidate_position_candidate1:
      fields: [candidate_id]
    fk_candidate_position_position1:
      fields: [position_id]

这个可以工作!有点问题 =/

复选框在创建和编辑页面中都可以显示,但数据无法保存。显然(?)我需要对模型进行一些自定义操作(lib/model/doctrine/candidate.class.php),这就是我失去焦点的地方。我不确定如何从candidate::save()中获取到candidate[positions]数据。

  • PHP 5.2.x
  • symfony 1.4.3

不确定这是否能解决问题,但请尝试将关系规范放在主表中而非参考表中,例如http://pastebin.com/CrL0GPrm -- 当我这样做时,在php symfony doctrine:build --all之后,admin-generator应用程序中的表单可以正常工作,无需进行任何修改。 - yitznewton
2个回答

1

我假设您首先创建了数据库模式,然后执行了build-schema命令。这样做不能正确地创建M:N之间的关系。因此,您需要在schema.yml中添加以下内容,然后重新构建您的模型、表单和构建器。

candidate:
  columns:
    id:
      type: integer(4)
      primary: true
      unsigned: true
      notnull: true
      autoincrement: true
    first_name:
      type: string(45)
      notnull: true
    last_name:
      type: string(45)
      notnull: true
    created_at:
      type: integer(4)
      unsigned: true
  relations:
    Position:
       refClass: candidatePosition
       local: candidate_id
       foreign: position_id

position:
  columns:
    id:
      type: integer(4)
      primary: true
      unsigned: true
      notnull: true
      autoincrement: true
    name:
      type: string(45)
  relations:
    Candidate:
       refClass: candidatePosition
       local: position_id
       foreign: candidate_id

谢谢你的回答。我的开发机器目前在电脑急救室。一旦它恢复健康,我将继续解决这个问题。 - Peter Bailey
你在哪里看到这个模式与文档相反?你试过吗? - Pabloks
哦,是的,我肯定试过了。Doctrine 的文档说:“Doctrine 只需要您在外键存在的一端指定关系。” 在我的情况下,那就是 candidate_position 表。你和 Dziamid 都让我把它们移到了被引用的表中。 - Peter Bailey
最后,不是外键存在的地方(那将是候选人或职位)。因此,在两端都定义关系并不是必要的,因为引用的话,“关系的相反端将在相反端反映和构建”。请检查示例中,关系在group模型中定义。 - Pabloks
  1. 实际上,第一个版本是由Doctrine Export Plugin for MySQL Workbench创建的(我喜欢通过可视化设计模式)。自那以后,我进行了手动调整。
  2. 是的。
- Peter Bailey
显示剩余8条评论

0
//schema.yml
Candidate:
  columns: ~
  relations:
    Position:
      alias: Positions
      refClass: CandidatePosition
      local: candidate_id
      foreign: position_id

Position:
  columns: ~
  relations:
    Candidate:
      alias: Candidates
      refClass: CandidatePosition
      local: position_id
      foreign: candidate_id

CandidatePosition:
  columns:
    candidate_id:
      type: integer(4)
      primary: true
    position_id:
      type: integer(4)
      primary: true

//CandidateForm class
  public function configure()
  {
    $this->getWidget('positions_list')->setOption('expanded', true);
  }

即使使用默认的generator.yml,它也应该立即正常工作。


感谢您的答复。我的开发机目前在电脑急诊室。一旦它恢复正常,我将继续解决这个问题。 - Peter Bailey
回到这个问题上。这并不能解决它。没有任何东西被保存,而且这直接违反了Doctrine自己在这个主题上的文档http://www.doctrine-project.org/projects/orm/1.2/docs/manual/yaml-schema-files/en#relationships:many-to-many。 - Peter Bailey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接