【问题标题】:Symfony Generator Forms, Doctrine, and M:N RelationshipsSymfony 生成器形式、学说和 M:N 关系
【发布时间】:2011-06-10 16:28:32
【问题描述】:

我有一个基本的 M:N 设置,其中包含三个表:候选、位置和候选位置。

这是来自 MySQL Workbench 的 ERD 的屏幕截图

现在,让我们继续讨论表单。在 symfony 生成器的默认世界中,这三个表都有一个单独的 CRUD 接口。但是,我不想为candidate_position 提供 CRUD 接口。

我想要的是,候选界面的创建和编辑操作包含一个多选字段(选择列表、复选框数组等),它将创建候选位置记录作为候选操作的一部分。

进入代码

config/doctrine/schema.yml (注意:不是整个schema.yml,只是这里讨论的表)

---
detect_relations: true
options:
  type: InnoDB

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:
    Positions:
      class: 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:
    Candidates:
      class: Candidate
      refClass: CandidatePosition
      local: position_id
      foreign: candidate_id


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
  indexes:
    fk_candidate_position_candidate1:
      fields: [candidate_id]
    fk_candidate_position_position1:
      fields: [position_id]

apps/backend/modules/candidate/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 }
        candidate_positions:  {label: Positions}
      list:    
        sort:  [last_name, asc]
      filter:  ~
      form:    
        display:
          "User": [first_name, last_name]
          "Applying For": [candidate_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['candidate_positions'] = new sfWidgetFormDoctrineChoice(
      array( 'multiple' => true, 'model' => 'Position', 'renderer_class' => 'sfWidgetFormSelectCheckbox' )
    );

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

这一切都有效,除了实际保存数据时。这就是我卡住的地方。

我显然需要做一些事情来创建/编辑/删除 CandidatePosition 记录,但我不确定从哪里开始工作。在candidateActions?覆盖Basecandidate::save()?

如果您可能需要查看任何其他数据,请告诉我。

  • PHP 5.2.x
  • symfony 1.4.3

【问题讨论】:

    标签: php symfony1 doctrine symfony-1.4 symfony-forms


    【解决方案1】:

    大约 10 个月前,我在连接表中的 M:N 关系和元数据方面遇到了类似的问题。

    我发现 melikedev 的那些博客条目非常有用!这与您的用例并不完全相同,但它可能会给您一些提示:

    http://melikedev.com/2009/12/09/symfony-w-doctrine-saving-many-to-many-mm-relationships/

    http://melikedev.com/2009/12/06/symfony-sfformextraplugin-select-double-list-maintain-order/

    http://melikedev.com/2010/04/06/symfony-saving-metadata-during-form-save-sort-ids/

    【讨论】:

      【解决方案2】:

      首先我可以建议升级 symfony 版本——我使用 1.4.11,你可以从头开始使用这个功能。

      如果这在您的情况下是不可能的,那么最好的方法是覆盖 CandidateForm 中的基本 doSave() 方法,如下所示:

      protected function doSave($con = null)
      {
          $existing = $this->object->Position->getPrimaryKeys();
          $values = $this->getValue('candidate_positions');
      
          $unlink = array_diff($existing, $values);
          $this->object->unlink('Position', array_values($unlink));
      
          $link = array_diff($values, $existing);
          $this->object->link('Position', array_values($link));
      
          parent::doSave($con);
      }
      

      您可能还需要在表单加载时手动设置选定的链接对象,如下所示:

      public function updateDefaultsFromObject()
      {
          parent::updateDefaultsFromObject();
      
          if (isset($this->widgetSchema['candidate_positions']))
          {
              $this->setDefault('candidate_positions', $this->object->Position->getPrimaryKeys());
          }
      }
      

      这应该可以解决问题。

      更新

      我认为由于更新到 1.4.11 没有帮助,架构定义存在一些问题,我的猜测是您需要像这样将关系定义添加到链接表“candidatePosition”:

        relations:
          Candidate:
            class: Candidate
            local: candidate_id
            foreign: id
            foreignAlias: Candidates
          Position:
            class: Position
            local: position_id
            foreign: id
            foreignAlias: Positions
      

      希望这会有所帮助。

      问候。

      【讨论】:

      • 好吧,我升级到了 1.4.11,运行了 cache-cleardoctrine:build --all-classes 并再次运行了页面。记录不保存。那么,当您说“从头开始”时,您到底是什么意思?
      • 嗯,这正是我的意思。您是否从 CandidateForm.class.php 中删除了额外的小部件声明 - 它们不是必需的。 ...如果这没有帮助,则架构声明中可能缺少某些内容。请参阅上面我的答案的编辑。
      • 好的,我试试。但是如何在模块的 generator.yml 中引用小部件?有命名约定之类的吗?
      • 一般来说,字段的名称就是widget的名称。尽管如此,您始终可以查看 BaseXxxForm.class.php 的源代码
      猜你喜欢
      • 2011-07-09
      • 1970-01-01
      • 1970-01-01
      • 2016-10-08
      • 2011-11-15
      • 1970-01-01
      • 1970-01-01
      • 2017-12-05
      • 1970-01-01
      相关资源
      最近更新 更多