Symfony 生成器形式、原则和 M:N 关系

发布于 2024-11-15 04:04:51 字数 3592 浏览 3 评论 0 原文

我有一个基本的 M:N 设置,包含三个表:candidate、position 和 Candidate_position。

以下是 MySQL Workbench 的 ERD 屏幕截图

http://dl.dropbox.com/u/180411/stackoverflow/erd.png

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

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

转到代码

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

I have a basic M:N setup with three tables: candidate, position, and candidate_position.

Here's a screenshot of the ERD from MySQL Workbench

http://dl.dropbox.com/u/180411/stackoverflow/erd.png

Now, moving on from that let's talk about forms. In the default world of symfony generator, you'd have a separate CRUD interface for all three of these tables. However, I don't want to have a CRUD interface for candidate_position.

What I want, is for the create and edit actions of the Candidate interface to contain a multi-choice field (select list, checkbox array, whatever) that would create the CandidatePosition records as part of the Candidate actions.

On to the code

config/doctrine/schema.yml (Note: the is not the entire schema.yml, but only the tables discussed here)

---
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 )
    );
  }
}

This all works, except when it comes to actually saving the data. This is the point where I get stuck.

I clearly need to do something to create/edit/delete the CandidatePosition records, but I'm not sure where to start working. In candidateActions? Override Basecandidate::save()?

Let me know if there's any other data you might need to see.

  • PHP 5.2.x
  • symfony 1.4.3

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

寒冷纷飞旳雪 2024-11-22 04:04:51

大约 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/

About 10 month ago I had similar trouble with M:N relationships and meta-data in the join table.

I found those blog entries of melikedev very useful! This is not exactly the same as your use case, but it might give you some hints:

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/

萝莉病 2024-11-22 04:04:51

首先,我建议升级 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

希望这有帮助。

问候。

first of all I can suggest an upgrade of symfony version - I use 1.4.11 where you'll have this functionality working from scratch.

If this is not possible in your case, the best place to this will be to override the base doSave() method in candidateForm like this:

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);
}

and also you'll probably need to manually set the selected link object on form load like this:

public function updateDefaultsFromObject()
{
    parent::updateDefaultsFromObject();

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

This should do the trick.

UPDATE

I think that since the update to 1.4.11 doesn't help, there is some problem with the schema definition and my guess is that you need to add relation definition to link table 'candidatePosition' like this:

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

Hope this helps.

Regards.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文