2015-10-13 2 views
8

Nous avons créé une collection en utilisant les formes propel et Symfony2. Nous pouvons enregistrer le formulaire sans aucun problème et nous pouvons ajouter une deuxième option en utilisant la collection. Si nous puis enregistrez puis essayer d'ajouter une 3ème collection nous obtenons l'erreur suivante:Symfony2 + Propel Collection undefined offset: 2

Notice: Undefined offset: 2 

Stack Trace

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

J'ai posté le code correspondant ci-dessous, mais comme il est calme une importante quantité de code. Nous nous demandions si quelqu'un avait connu le même problème.

J'ai envoyé un rapport de bogue avec un autre bit de code qui a créé la même erreur mais je n'ai reçu aucune réponse. Le rapport de bug est here.

C'est un extrait du schéma correspondant:

<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> 

est le point de vue ci-dessous (sans style):

{{ 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> 

Le formulaire traitant ceci:

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

Enfin, ci-dessous est le contrôleur.

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())); 
    } 
+0

et votre code 'BaseLabelsLabelsLinesMapsQuery.php' est? – Alex

+0

@Alex car il y a un petit nombre de lignes dans le script que j'ai copié dans pastebin. http://pastebin.com/WXgfN7yf. Veuillez noter que ce code est entièrement généré par Propel. –

Répondre

1

Votre schéma est un peu déroutant pour moi. Ce bit ci-dessous comprend trois clés primaires avec deux d'entre eux comme une clé étrangère et l'un d'entre eux comme identifiant unique pour la ligne:

<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> 

je soupçonne que beaucoup de vos problèmes peuvent aller si vous choisissez une chose et respectez-le. Supprimez id et demandez à votre clé composite primaire de représenter deux tables étrangères, ce qui est parfaitement valide, ou modifiez vos contraintes PRIMARY KEY s à UNIQUE sur chacune de vos clés étrangères, en laissant votre clé primaire sous la forme id. Ceci est également parfaitement valide.En fin de compte, votre décision sera basée sur vos exigences de conception.

Autre remarque: Vous pouvez ou ne souhaitez pas effectuer un heavyIndexing, en particulier si vous référencez des colonnes individuelles dans la clé primaire. Une clé primaire composite crée un index sur les trois colonnes et non individuellement. Cela peut ou peut ne pas être important dans votre projet, mais je pensais que ça valait le coup de le souligner.

+0

Bonjour, merci pour la mention heavyIndexing. Je ne l'ai jamais utilisé, alors je vais y jeter un coup d'œil. À l'origine, je suivais le schéma suivant (propelorm.org/documentation/cookbook/symfony2/mastering-symfony2-forms-with-propel.html#many-to-many-relations) Cependant, comme vous l'avez souligné. Id n'est pas réellement dans le schéma plusieurs à plusieurs. Je crois que cela pourrait être la cause profonde du problème. Je vais jeter un coup d'oeil et revenir à vous. –

0

Je ne suis pas sûr à 100%, mais je suis assez certain que ce soit parce que cette ligne:

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

Vous remarquerez dans la méthode findPkSimple dans votre classe BaseQuery est Attendant que la clé variable soit un tableau avec 3 valeurs (indices 0, 1, 2)

La raison pour laquelle je ne suis pas sûr est que je ne sais pas si $ id est juste une valeur ou un tableau comme définition de la fonction vous avez ne pas restreindre sur le type. (votre fonction editAction)

Je pense, parce que vous avez trois clés primaires, la classe qui est générée s'attend à ce que vous ayez trois valeurs individuelles lors de la recherche par clé primaire.

Il pourrait être plus efficace si vous avez seulement une clé primaire, puis un index unique sur ces trois colonnes pour garantir l'unicité (si c'est ce que vous allez pour)

+0

Juste pour clarifier que $ id est un identifiant unique et non un tableau. Comme pour avoir une clé primaire. J'ai pris ce qui suit d'ici (propelorm.org/documentation/cookbook/symfony2/mastering-symfony2-forms-with-propel.html#many-to-many-relations) qui montre les multiples clés primaires. Cependant, id n'est pas réellement sur cette carte dans cet exemple. –

+0

Je pense que cet exemple peut être soit périmé, soit complètement erroné. Dans leur exemple, ils ont une clé primaire qui est aussi une clé étrangère. – William