Mots-clé : symfony 2

Symfony 2 Embedded Forms: Catchable Fatal Error: Argument 1 passed to Entity::addProperty must be an instance of XX\MyClass, array given

Encore une abstraction qui fuit.

Si jamais vous avec un problème avec un ManyToMany et que vous rencontrez une erreur du type : Symfony 2 Embedded Forms: Catchable Fatal Error: Argument 1 passed to Entity::addProperty must be an instance of XX\MyClass, array given, c’est que vous avez peut-être le même problème que moi, à savoir : une mauvaise déclaration de votre type de formulaire.

Enfin… mauvaise… disons qu’il manque des choses, et que logiquement, tant qu’on n’a pas une connaissance parfaite des rouages de Symfony, on ne comprend pas pourquoi ça ne fonctionne pas.

Je vais donc vous dire ce qu’il me manquait : j’avais une table personne et une table adresse.
Ces deux tables étaient reliées par une relation ManyToMany : une personne peut avoir une ou plusieurs adresses, et à une même adresse, plusieurs personnes peuvent habiter (heureusement ! 😉 ).

Dans la déclaration du type d’adresse, tout semblait cohérent, il n’y avait aucune erreur, mais il manquait une seule chose : la fonction setDefaultOption(). Je vous la fais courte : le code qui suit fonctionne.

Même si cette astuce ne fonctionne pas pour vous, essayez de suivre mon raisonnement : j’ai refait complètement un projet en partant de zéro, en suivant les instructions ici (Symfony 2 : Comment imbriquer une Collection de Formulaires) : et ensuite j’ai comparé pas à pas avec mon code. Pour en arriver aux six petites lignes qui manquaient : la fonction setDefaultOption().

<?php

namespace MaSociete\Bundle\MyBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver;
use Symfony\Component\Form\FormBuilderInterface;

class AdresseType extends AbstractType
{
   /**
    * Builds the form.
    *
    * This method is called for each type in the hierarchy
    * starting form the top most type. Type extensions can
    * further modify the form.
    *
    * @see FormTypeExtensionInterface::buildForm()
    *
    * @param FormBuilderInterface $builder The form builder
    * @param array                $options The options
    */
    public function buildForm(
        FormBuilderInterface $builder,
        array $options
    ) {
        $builder->add('adresse1', 'text')
            ->add('adresse2', 'text')
            ->add('cp', 'text')
            ->add('ville', 'text');
        }
    public function setDefaultOptions(
        \Symfony\Component\OptionsResolver\OptionsResolverInterface $resolver
    ) {
        $resolver->setDefaults(array(
            'data_class' => 'MaSociete\Bundle\MyBundle\Entity\Adresse',
        ));
    }
    public function getDefaultOptions(array $options)
    {
        return array(
            'data_class' => 'MaSociete\Bundle\MyBundle\Entity\Adresse',
        );
    }
    public function getName()
    {
        return 'adresse';
    }
}

Symfony 2 Notice: Undefined offset: 0 in vendor/…/Hydration/SimpleObjectHydrator.php line 103

Voici un petit problème que j’ai résolu.

Supposons que vous ayez plusieurs entités qui descendent d’une seule.
Dans l’entité mère, vous précisez ce qui va différencier les autres via la propriété DiscriminatorColumn :

/**
 * @ORM\Entity
 * @ORM\Table(name="table_de_base")
 * @ORM\InheritanceType("JOINED")
 * @ORM\Entity(
 *   repositoryClass="SOCIETE\Bundle\MegaSuperBundle\Repository\PersonRepository"
 * )
 * @ORM\DiscriminatorColumn(name="person_type", type="integer")
 * @ORM\DiscriminatorMap({"1" = "PersonneBoss", "2" = "PersonneLarbin"})
 */
abstract class Personne extends BaseUser
{
...
}

Cela signifie en clair : l’entité «PersonneBoss», descendante de «Personne», aura aura la valeur «1» dans le champ person_type, et l’entité descendante «PersonneLarbin», de «Personne», aura la valeur «2» dans le champ person_type. C’est, comme son nom l’indique, un «discriminateur».

Si jamais vous vous retrouvez avec une erreur de ce type : Notice: Undefined offset: 0 in vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/SimpleObjectHydrator.php line 103, alors il se peut, comme c’était le cas pour moi, que les valeurs pour le «discriminateur» n’aient pas été correctement renseignées : dans mon cas, les valeurs étaient soit null, soit 0 et en fait cette valeur sert apparemment d’indice dans une table afin de pouvoir faire la jointure avec les descendants : donc il essayait de chercher une table avec l’indice 0, alors que je n’ai précisé que 1PersonneBoss») ou 2PersonneLarbin»)… donc pour la valeur 0, forcément, Symfony sort un Notice: Undefined offset: 0.

Bref, si vous avez une erreur comme celle-là, vérifiez que les valeurs en base de données sont cohérentes avec vos déclarations !

symfony 2 : isset et null avec Twig

Une des questions qu’on cherche le plus souvent avec Twig, c’est comment vérifier si une variable existe ou pas ?

La réponse se fait en trois étapes :

  1. Vérifier si une variable existe (= si elle a été initialisée) :
    En php, c’est isset().
    En Twig, c’est defined.
    Exemple de code Twig :

    {% if app.user is defined %}
    Code html
    {% endif %}
  2. Vérifier si une variable n’est pas null (= elle est définie, mais contient la valeur null) :
    En php, c’est !is_null().
    En Twig, c’est is not null.
    Exemple de code Twig :

    {% if app.user is not null%}
    Code html
    {% endif %}
  3. Vérifier si une variable existe et qu’elle n’est pas null (= elle est définie, et contient autre chose que la valeur null) :
    En php, c’est isset() && (!is_null()).
    En Twig, c’est is defined and is not null.
    Exemple de code Twig :

    {% if app.user is defined and app.user is not null%}
    Code html
    {% endif %}

En espérant que cela aide du monde !

Symfony: The form’s view data is expected to be of type scalar, array or an instance of \ArrayAccess, but is…

J’ai eu l’erreur qui est le titre de mon post.

Pourtant, j’avais tout fait correctement. J’avais mis en place une collection ManyToMany simple : un partenaire peut être relié à une ou plusieurs personnes et une personne peut être reliée à un ou plusieurs partenaires.

Sur symfony 2.1, tout fonctionnait correctement, et j’ai fait la mise à jour sur symfony 2.3 (pour rester à la pointe 😉 ) mais là une erreur apparaissait :

« The form’s view data is expected to be of type scalar, array or an instance of \ArrayAccess, but is an instance of class HQF\Bundle\PizzasBundle\Entity\Personne. You can avoid this error by setting the « data_class » option to « HQF\Bundle\PizzasBundle\Entity\Personne » or by adding a view transformer that transforms an instance of class HQF\Bundle\PizzasBundle\Entity\Personne to scalar, array or an instance of \ArrayAccess. »

Après un bon moment de recherche, j’ai trouvé ma solution ici.

Dans mon bundle j’avais mon fichier « Bundle/Form/Type/PartenaireType.php » dans lequel j’avais déclaré tout comme il fallait :

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('nom',                    'text');
        $builder->add('site_actif',             'checkbox');
        $builder->add('afficher_img_produits',  'checkbox');
        $builder->add('commande_en_ligne',      'checkbox');
        $builder->add('livraison',              'checkbox');
        $builder->add('livraison_delai',        'integer');
        $builder->add(
            'personnes',
            'collection',
            array(
                'type' => new PersonneType(),
            )
        );
    }

Tout était parfait, et fonctionnait sous Symfony 2.1. Mais lors de la mise à jour, ça ne fonctionnait plus. Il manquait cela : préciser à nouveau que la PersonneType était liée à un type Personne :

'options' => array('data_class' => 'HQF\Bundle\PizzasBundle\Entity\Personne')

Donc dans mon code ça donne ça :

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('nom',                    'text');
        $builder->add('site_actif',             'checkbox');
        $builder->add('afficher_img_produits',  'checkbox');
        $builder->add('commande_en_ligne',      'checkbox');
        $builder->add('livraison',              'checkbox');
        $builder->add('livraison_delai',        'integer');
        $builder->add(
            'personnes',
            'collection',
            array(
                'type' => new PersonneType(),
                'options' => array(
                    'data_class' => 'HQF\Bundle\PizzasBundle\Entity\Personne'
                ),
            )
        );
    }

Un grand merci à Stackoverflow, sinon j’aurais mis bien plus de temps à m’en sortir, je pense !

Symfony 2 : mon site de démonstration est sorti : livrepizzas

Mon site de démonstration pour l’utilisation du framework Symfony 2 est sorti.

http://www.livrepizzas.fr

Ce n’est qu’un site de démonstration, il est loin d’être parfait !

  • Bien sûr il est optimisé pour google et pour les mobiles et tablettes.
  • Bien sûr il est compatible w3c.
  • Bien sûr il est moderne et utilise du HTML5.
  • Bien sûr il est en responsive design.
  • Bien sûr c’est facile à faire. 🙂

Si vous avez des commentaires ou suggestions à faire, n’hésitez pas !

Symfony: Could not open input file: composer.phar solution

Si jamais vous avez ce problème, une solution qui peut fonctionner est de lancer un shell, et d’aller dans votre répertoire source.
De là, lancez cet ordre :

curl -s http://getcomposer.org/installer | php

Et tout rentrera dans l’ordre !