web-dev-qa-db-fra.com

Valeur par défaut dans Doctrine

Comment définir une valeur par défaut dans Doctrine 2?

296
Jiew Meng

Les valeurs par défaut de la base de données ne sont pas "supportables". La seule façon d'utiliser les valeurs par défaut de la base de données consiste à utiliser l'attribut de mappage columnDefinition pour spécifier le fragment SQL (DEFAULT cause inclus) de la colonne à laquelle le champ est mappé.

Vous pouvez utiliser:

<?php
/**
 * @Entity
 */
class myEntity {
    /**
     * @var string
     *
     * @Column(name="myColumn", type="string", length="50")
     */
    private $myColumn = 'myDefaultValue';
    ...
}

Les valeurs par défaut de niveau PHP sont préférables car elles sont également correctement disponibles sur les objets nouvellement créés et persistants (Doctrine ne reviendra pas dans la base de données après la persistance d'un nouvel objet pour obtenir les valeurs par défaut).

355
romanb
<?php
/**
 * @Entity
 */
class myEntity {
    /**
     * @var string
     *
     * @ORM\Column(name="myColumn", type="integer", options={"default" : 0})
     */
    private $myColumn;
    ...
}

Notez que cela utilise SQL DEFAULT, qui n'est pas pris en charge pour certains champs comme BLOB et TEXT.

457
iv3ndy

Configurez un constructeur dans votre entité et définissez-y la valeur par défaut.

61
Jeremy Hicks

Utilisation: 

options={"default":"foo bar"}

et pas: 

options={"default"="foo bar"}

Par exemple:

/**
* @ORM\Column(name="foo", type="smallint", options={"default":0})
*/
private $foo
53

Mettre à jour

Une raison de plus pour laquelle lire la documentation de Symfony ne sera jamais hors de tendance. Il existe une solution simple pour mon cas spécifique et consiste à définir l'option field typeempty_data sur une valeur par défaut.

Là encore, cette solution concerne uniquement le scénario dans lequel une entrée vide dans un formulaire définit le champ de base de données sur null.

Contexte

Aucune des réponses précédentes ne m'a aidé avec mon scénario spécifique mais j'ai trouvé une solution.

J'avais un champ de formulaire qui devait se comporter comme suit:

  1. Non requis, peut être laissé en blanc. (Used 'required' => false)
  2. Si laissé vide, il devrait utiliser par défaut une valeur donnée. Pour une meilleure expérience utilisateur, je n'ai pas défini la valeur par défaut dans le champ de saisie, mais plutôt utilisé l'attribut html "placeholder", car il est moins gênant.

J'ai ensuite essayé toutes les recommandations données ici. Laissez moi les lister:

  • Définissez une valeur par défaut pour la propriété entity:
<?php
/**
 * @Entity
 */
class myEntity {
    /**
     * @var string
     *
     * @Column(name="myColumn", type="string", length="50")
     */
    private $myColumn = 'myDefaultValue';
    ...
}
  • Utilisez les options d'annotation:
@ORM\Column(name="foo", options={"default":"foo bar"})
  • Définissez la valeur par défaut sur le constructeur:
/**
 * @Entity
 */
class myEntity {
    ...
    public function __construct()
    {
        $this->myColumn = 'myDefaultValue';
    }
    ...
}

IMPORTANT

Les champs de formulaire Symfony remplacent les valeurs par défaut définies dans la classe Entity. Cela signifie que votre schéma pour votre base de données peut avoir une valeur par défaut définie, mais si vous laissez un champ non obligatoire vide lors de la soumission de votre formulaire, le form->handleRequest() de votre méthode form->isValid() remplacera les valeurs par défaut de votre classe Entity et sera défini. les aux valeurs du champ d'entrée. Si les valeurs du champ d'entrée sont vides, la propriété Entity sera définie sur null.

http://symfony.com/doc/current/book/forms.html#handling-form-submissions

Ma solution de contournement

Définissez la valeur par défaut sur votre contrôleur après form->handleRequest() dans votre méthode form->isValid():

...
if ($myEntity->getMyColumn() === null) {
    $myEntity->setMyColumn('myDefaultValue');
}
...

Pas une belle solution mais ça marche. Je pourrais probablement créer un validation group, mais il se peut que certaines personnes considèrent ce problème comme une transformation data plutôt que comme une validation data. Je vous laisse le soin de décider.


Remplacer le poseur (ne fonctionne pas)

J'ai aussi essayé de remplacer le setter Entity de cette façon:

...
/**
 * Set myColumn
 *
 * @param string $myColumn
 *
 * @return myEntity
 */
public function setMyColumn($myColumn)
{
    $this->myColumn = ($myColumn === null || $myColumn === '') ? 'myDefaultValue' : $myColumn;

    return $this;
}
...

Ceci, même si cela a l'air plus propre, ça ne marche pas. La raison en est que la méthode evil form->handleRequest() n'utilise pas les méthodes de définition du modèle pour mettre à jour les données (Dig into form->setData() pour plus de détails).

48
Callistino

La solution de contournement que j'ai utilisée était une LifeCycleCallback. J'attends toujours de voir s'il existe une méthode "native", par exemple @Column(type="string", default="hello default value").

/**
 * @Entity @Table(name="posts") @HasLifeCycleCallbacks
 */
class Post implements Node, \Zend_Acl_Resource_Interface {

...

/**
 * @PrePersist
 */
function onPrePersist() {
    // set default date
    $this->dtPosted = date('Y-m-d H:m:s');
}
17
Jiew Meng

Vous pouvez aussi le faire en utilisant XML:

<field name="acmeOne" type="string" column="acmeOne" length="36">
    <options>
        <option name="comment">Your SQL field comment goes here.</option>
        <option name="default">Default Value</option>
    </options>
</field>
12
Andrew Zhilin

Voici comment je l'ai résolu pour moi-même. Vous trouverez ci-dessous un exemple d'entité avec une valeur par défaut pour MySQL. Cependant, cela nécessite également la configuration d'un constructeur dans votre entité et la définition de la valeur par défaut à cet endroit.

Entity\Example:
  type: entity
  table: example
  fields:
    id:
      type: integer
      id: true
      generator:
        strategy: AUTO
    label:
      type: string
      columnDefinition: varchar(255) NOT NULL DEFAULT 'default_value' COMMENT 'This is column comment'
7
Putna

Fonctionne pour moi sur une base de données mysql également:

Entity\Entity_name:
    type: entity
    table: table_name
    fields: 
        field_name:
            type: integer
            nullable: true
            options:
                default: 1
7
Alex Hoang

Rien de tout cela n'a fonctionné pour moi. J'ai trouvé une documentation sur le site de la doctrine qui dit de définir directement la valeur pour définir une valeur par défaut.

http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/reference/faq.html

private $default = 0;

Cela a inséré la valeur que je voulais.

5
metric152

Si vous utilisez la définition de yaml pour votre entité, les éléments suivants fonctionnent pour moi sur une base de données postgresql:

Entity\Entity_name:
    type: entity
    table: table_name
    fields: 
        field_name:
            type: boolean
            nullable: false
            options:
                default: false
3
wonzbak

Ajout à la réponse brillante de @romanb.

Cela ajoute un peu de surcharge dans la migration, car vous ne pouvez évidemment pas créer de champ avec une contrainte non nulle et sans valeur par défaut.

// this up() migration is autogenerated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != "postgresql");

//lets add property without not null contraint        
$this->addSql("ALTER TABLE tablename ADD property BOOLEAN");

//get the default value for property       
$object = new Object();
$defaultValue = $menuItem->getProperty() ? "true":"false";

$this->addSql("UPDATE tablename SET property = {$defaultValue}");

//not you can add constraint
$this->addSql("ALTER TABLE tablename ALTER property SET NOT NULL");

Avec cette réponse, je vous encourage à penser pourquoi vous avez besoin de la valeur par défaut dans la base de données en premier lieu? Et généralement, cela permet de créer des objets avec une contrainte non nulle.

2
Dziamid

Bien que définir la valeur dans le constructeur fonctionne, l’utilisation des événements Doctrine Lifecycle peut constituer une meilleure solution.

En exploitant l'événement prePersist Lifecycle, vous pouvez définir votre valeur par défaut sur votre entité uniquement lors de la persistance initiale.

1
tiruncula

J'ai lutté avec le même problème. Je voulais avoir la valeur par défaut de la base de données dans les entités (automatiquement). Devinez quoi, je l'ai fait :)

<?php
/**
 * Created by JetBrains PhpStorm.
 * User: Steffen
 * Date: 27-6-13
 * Time: 15:36
 * To change this template use File | Settings | File Templates.
 */

require_once 'bootstrap.php';

$em->getConfiguration()->setMetadataDriverImpl(
    new \Doctrine\ORM\Mapping\Driver\DatabaseDriver(
        $em->getConnection()->getSchemaManager()
    )
);

$driver = new \Doctrine\ORM\Mapping\Driver\DatabaseDriver($em->getConnection()->getSchemaManager());
$driver->setNamespace('Models\\');

$em->getConfiguration()->setMetadataDriverImpl($driver);

$cmf = new \Doctrine\ORM\Tools\DisconnectedClassMetadataFactory();
$cmf->setEntityManager($em);
$metadata = $cmf->getAllMetadata();

// Little hack to have default values for your entities...
foreach ($metadata as $k => $t)
{
    foreach ($t->getFieldNames() as $fieldName)
    {
        $correctFieldName = \Doctrine\Common\Util\Inflector::tableize($fieldName);

        $columns = $tan = $em->getConnection()->getSchemaManager()->listTableColumns($t->getTableName());
        foreach ($columns as $column)
        {
            if ($column->getName() == $correctFieldName)
            {
                // We skip DateTime, because this needs to be a DateTime object.
                if ($column->getType() != 'DateTime')
                {
                    $metadata[$k]->fieldMappings[$fieldName]['default'] = $column->getDefault();
                }
                break;
            }
        }
    }
}

// GENERATE PHP ENTITIES!
$entityGenerator = new \Doctrine\ORM\Tools\EntityGenerator();
$entityGenerator->setGenerateAnnotations(true);
$entityGenerator->setGenerateStubMethods(true);
$entityGenerator->setRegenerateEntityIfExists(true);
$entityGenerator->setUpdateEntityIfExists(false);
$entityGenerator->generate($metadata, __DIR__);

echo "Entities created";
1
Steffen Brem

Soyez prudent lorsque vous définissez des valeurs par défaut pour la définition de la propriété! Faites-le dans le constructeur à la place, pour le garder sans problèmes. Si vous le définissez dans la définition de la propriété, conservez l'objet dans la base de données, effectuez un chargement partiel. Les propriétés non chargées auront à nouveau la valeur par défaut. Cela est dangereux si vous souhaitez conserver l'objet à nouveau.

0
tomazahlin