Symfony2 + Propel Collection 未定义的偏移量:2

Symfony2 + Propel Collection undefined offset: 2

我们使用 propel 和 Symfony2 形式创建了一个集合。我们可以毫无问题地保存表单,我们可以使用集合添加第二个选项。如果我们保存然后尝试添加第三个集合,我们会收到以下错误:

Notice: Undefined offset: 2 

堆栈跟踪

in src/app/MyBundle/Model/om/BaseLabelsLabelsLinesMapsQuery.php at line 241  

$cton0 = $this->getNewCriterion(LabelsLabelsLinesMapsPeer::ID, $key[0], Criteria::EQUAL);
            $cton1 = $this->getNewCriterion(LabelsLabelsLinesMapsPeer::LABEL_ID, $key[1], Criteria::EQUAL);
            $cton0->addAnd($cton1);
            $cton2 = $this->getNewCriterion(LabelsLabelsLinesMapsPeer::LABEL_LINES_ID, $key[2], Criteria::EQUAL);
            $cton0->addAnd($cton2);
            $this->addOr($cton0);
        }

我已经在下面发布了相关代码,但是由于代码量很大。我们想知道是否有人遇到过同样的问题。

我已经发送了一份错误报告,其中包含一段不同的代码,它产生了同样的错误,但我没有收到任何回复。错误报告是 here

这是相关架构的片段:

<table name="labels_labels_lines_maps" isCrossRef="true">
    <column name="id"
            type="integer"
            required="true"
            autoIncrement="true"
            primaryKey="true"/>
    <column name="label_id"
            type="integer"
            primaryKey="true"/>
    <column name="label_lines_id"
            type="integer"
            primaryKey="true"/>
    <foreign-key foreignTable="labels" onDelete="cascade">
        <reference local="label_id" foreign="id"/>
    </foreign-key>
    <foreign-key foreignTable="labels_lines" onDelete="cascade">
        <reference local="label_lines_id" foreign="id"/>
    </foreign-key>
    <vendor type="mysql">
        <parameter name="Engine" value="InnoDB" />
        <parameter name="Charset" value="utf8" />
    </vendor>
</table>

<table name="labels_lines">
    <column name="id"
            type="integer"
            required="true"
            autoIncrement="true"
            primaryKey="true"/>
    <column name="placeholder_text"
            type="varchar"
            size="150"/>
    <column name="font_id"
            type="integer"/>
    <column name="font_size"
            type="integer"/> 
    <column name="x_axis"
            type="integer"/>  
    <column name="y_axis"
            type="integer"/>
    <column name="width"
            type="integer"/>      
    <column name="height"
            type="integer"/>       
    <column name="colour"
            type="varchar"
            size="20"/>        
    <column name="angle"
            type="integer"/> 
    <column name="is_volume"
            type="boolean"/>
    <column name="is_percentage"
            type="boolean"/>
    <column name="is_productof"
            type="boolean"/>
    <column name="is_type"
            type="boolean"/>
    <column name="is_occasion"
            type="boolean"/>        
    <foreign-key foreignTable="font" onDelete="cascade">
        <reference local="font_id" foreign="id"/>
    </foreign-key>
    <vendor type="mysql">
        <parameter name="Engine" value="InnoDB" />
        <parameter name="Charset" value="utf8" />
    </vendor>
</table>

<table name="occasion">
    <column name="id"
            type="integer"
            required="true"
            autoIncrement="true"
            primaryKey="true"/>
    <column name="occasion"
            type="varchar"
            size="200"/>

    <vendor type="mysql">
        <parameter name="Engine" value="InnoDB" />
        <parameter name="Charset" value="utf8" />
    </vendor>
</table>

<table name="font">
    <column name="id"
            type="integer"
            required="true"
            autoIncrement="true"
            primaryKey="true"/>
    <column name="name"
            type="varchar"
            size="100"/>
    <column name="location"
            size="300"/>
    <vendor type="mysql">
        <parameter name="Engine" value="InnoDB" />
        <parameter name="Charset" value="utf8" />
    </vendor>
</table>

下面是视图(没有任何样式):

{{ form_start(form) }}
{{ form_row(form._token) }}
<ul class="labelsliness list-group" data-prototype="{{ form_widget(form.labelsliness.vars.prototype)|e }}">
                    {% for lines in form.labelsliness %}
                        <li>{{ form(lines) }}</li>
                    {% endfor %}
                </ul>

                {{ form_row(form.save) }}

{{ form_end(form) }}

<script>
                    var $collectionHolder;

                    var $addLinesLink = $('<button class="add_line_link btn btn-primary">Add a line</button>');
                    var $newLinkLi = $('<li></li>').append($addLinesLink);

                    $(document).ready(function(){
                       $collectionHolder = $('ul.labelsliness');

                       $collectionHolder.append($newLinkLi);

                       $collectionHolder.data('index', $collectionHolder.find(':input').length);

                       $addLinesLink.on('click', function(e) {
                          e.preventDefault();

                          addLineForm($collectionHolder, $newLinkLi);
                       });
                    });

                    function addLineForm($collectionHolder, $newLinkLi) {
                        var prototype = $collectionHolder.data('prototype');

                        var index = $collectionHolder.data('index');

                        var newForm = prototype.replace('/__name__/g', index);

                        $collectionHolder.data('index', index + 1);

                        var $newFormLi = $('<li></li>').append(newForm);

                        $newFormLi.append('<button class="remove-line btn btn-danger">Remove</button>');

                        $newLinkLi.before($newFormLi);

                        $('.remove-line').click(function(e){
                           e.preventDefault();

                           $(this).parent().remove();

                           return false;
                        });
                    }
                </script>

处理这个的表单:

public function buildForm(FormBuilderInterface $builder, array $options)
    {
       $builder
               ->add("labelsliness", "collection", array(
                   "type" => new LabelsLinesType(),
                   "allow_add" => true,
                   "allow_delete" => true,
                   "by_reference" => false
               ))
               ->add("save", "submit");
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'AJSharp\EPCBundle\Model\Labels',
        ));
    }

    public function getName()
    {
        return "label_form";
    }

最后,下面是控制器。

public function editAction(Request $request, $id = null)
    {

        $labels = LabelsQuery::create()->findPk($id);

        $form = $this->createForm(new EditLabelType(), $labels);

        $form->handleRequest($request);

        if ($form->isValid()) {

            $labels->save();
            return $this->redirect($this->generateUrl("_admin_labels"));
        }

        return $this->render("AppLabelBundle:Admin:edit.html.twig", array("form" => $form->createView()));
    }

我不是 100% 确定这一点,但我相当确定这是因为这一行:

$labels = LabelsQuery::create()->findPk($id);

您会在 BaseQuery 的 findPkSimple 方法中注意到 class 它期望变量键是一个具有 3 个值(索引 0、1、2)的数组

我不确定的原因是我不知道 $id 只是一个值还是一个数组,因为你的函数定义没有类型限制。 (您的 editAction 函数)

我认为,因为您有三个主键,所以生成的 class 希望您在按主键搜索时具有三个单独的值。

如果您只有一个主键,然后在这三列上使用唯一索引以确保唯一性(如果这就是您的目的),可能会更有效

你的模式让我有点困惑。下面的这一点包括三个主键,其中两个作为外键,一个作为行的唯一标识符:

<table name="labels_labels_lines_maps" isCrossRef="true">
    <column name="id"
            type="integer"
            required="true"
            autoIncrement="true"
            primaryKey="true"/>
    <column name="label_id"
            type="integer"
            primaryKey="true"/>
    <column name="label_lines_id"
            type="integer"
            primaryKey="true"/>
    <foreign-key foreignTable="labels" onDelete="cascade">
        <reference local="label_id" foreign="id"/>
    </foreign-key>
    <foreign-key foreignTable="labels_lines" onDelete="cascade">
        <reference local="label_lines_id" foreign="id"/>
    </foreign-key>
    <vendor type="mysql">
        <parameter name="Engine" value="InnoDB" />
        <parameter name="Charset" value="utf8" />
    </vendor>
</table>

我怀疑如果你选择一件事并坚持下去,你的很多麻烦可能会消失。要么删除 id 并让你的主复合键代表两个外部表,这是完全有效的,或者将你的 PRIMARY KEYs 更改为每个外键的 UNIQUE 约束,留下你的主键作为 id。这也是完全正确的。最终您的决定将基于您的设计要求。

另一个注意事项:您可能想也可能不想做 heavyIndexing,尤其是当您引用主键中的各个列时。复合主键针对所有三列创建索引,而不是单独创建索引。这在您的项目中可能重要也可能不重要,但我认为值得指出。