认证对象上的非对象错误

I'm working on a Symfony form with non-entity fields (in a collection).

(EDIT: All the code below is now working well!)

What we're talking about

For comprehension this is some code snippets : Form definition (in PieceType class):

// Form\Type\PieceType.php

$builder
    ->add('name',
          'text',
          array('max_length' => 70,
                'label' => "piece.name"))
    ->add('compositors',
          'collection',
          array('type' => 'entity',
                'options' => array('class' => 'kalisonStdArchiveBundle:Person',
                                   'property_path' => false),
          'allow_add' => true,
          'allow_delete' => true,
          'property_path' => false,
          'by_reference' => false,
          'label' => 'piece.compositor'
    ));

The compositors fields are added using javascript, using the data-prototype (explained here).

The rendering is simply done using that view:

// Resources\views\Piece\piece.new.html.twig

{% block javascripts %}
{{ parent() }}
<script type="text/javascript">var nbCompositors = {{ form.compositors|length }}</script>
<script type="text/javascript" src="{{ asset('bundles/kalisonstdarchive/js/piece.new.js') }}"></script>
{% endblock javascripts %}

{% block main %}
<form novalidate action="{{ path("kalisonStdArchiveBundle_piece_new") }}" method="post" {{ form_enctype(form) }}>
    {{ form_widget(form) }}
    <button id="add-compositor">{{ "compositor.add"|trans }}</button>
    <input type="submit" id="submit" value="{{ "piece.create"|trans }}" name="submit" />
</form>
{% endblock %}

The javascript associated is:

// Resources\public\js\piece.new.js

$(document).ready(function() {
    jQuery('#add-compositor').click(function() {
        var list = jQuery('#kalison_stdarchivebundle_piecetype_compositors');
        var newCompositor = list.attr('data-prototype');
        newCompo = newCompositor.replace(/\$\$name\$\$/g, nbCompositors);
        nbCompositors++;
        var html = jQuery('<p></p>').html(newCompositor);
        html.appendTo(jQuery('#kalison_stdarchivebundle_piecetype_compositors'));
        return false;
    });
});

And here is the action which manage the datas. As notified by @l3l0, I wasn't checking last iteration, which causes a $addCompositor null:

// Controller\PieceController.php

$newPiece = new Piece();
$form = $this->get('form.factory')->create(new PieceType(), $newPiece);

if ('POST' == $request->getMethod()) {
    $form->bindRequest($request);

    if ($form->isValid()) { 
        $this->get('piece_manager')->savePiece($newPiece);

        if ($form["compositors"] != null) { 
            foreach ($form["compositors"] as $formCompositor) {
                $addCompositor = $formCompositor->getData();
                if ($addCompositor != null) {
                    $newPerfomance = new Performance();
                    $newPerfomance->setPerson($addCompositor); // Throw Catchable Fatal Error
                    $newPerfomance->setPiece($newPiece);
                    $newPerfomance->setInstrument($instrument);
                    $this->get('performance_manager')->savePerformance($newPerfomance);
                }
            }
        }
    }
}

My problem is that I got a Symfony error telling that: Argument 1 passed to Performance::setPerson() must be an instance of Person, null given. (Of course, the method in Performance class is public function setPerson(Person $person))

What I've tried

  • I tried to check for sure: if (!is_object($addCompositor)) throw new Exception('NOT AN OBJECT');

    And yes, $addCompositor is really an object.

  • I assumed it was an incompatible object, but if try to print the object: var_dump($addCompositor).

    I'm not surprised to get: object(...\Entity\Person)

  • finally my last test was to call a method on this object: echo $addCompositor->getLastName();.

    Worked as well, printing the name - and just after throw this well known error: Call to a member function getLastName() on a non-object.

So, my code looks like that now:

foreach ($form["compositors"] as $formCompositor) {
    $addCompositor = $formCompositor->getData();
    if (!is_object($addCompositor))
        throw new Exception('NOT AN OBJECT'); // Not throwing: it's an object
    var_dump($addCompositor); // Print a Person object
    echo $addCompositor->getLastName(); // Print the name, then break on "non-object" error
    $newPerfomance = new Performance();
    $newPerfomance->setPerson($addCompositor); // Throw Catchable Fatal Error
    $newPerfomance->setPiece($newPiece);
    $newPerfomance->setInstrument($instrument);
    $this->get('performance_manager')->savePerformance($newPerfomance);
}

Where is your god now?

At first I thought it was a Symfony bug, but with that last test I'm a bit confused. Have you ever been facing that?

It seems that in next iterations you just not have data object.

Please check what data are submitted and show us JS code too. You can check what is in $form["compositors"] too

Ah can you tell which version of Symfony do you use? (2.0.x, 2.1 ?)