Comment définir une valeur par défaut dans Doctrine 2?
Comment définir une valeur par défaut dans Doctrine 2?
Réponses:
Les valeurs par défaut de la base de données ne sont pas "portables" prises en charge. La seule façon d'utiliser les valeurs par défaut de la base de données consiste à utiliser l' columnDefinition
attribut de mappage dans lequel vous spécifiez l' SQL
extrait de code ( DEFAULT
cause incluse) pour 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 au niveau PHP sont préférées car elles sont également correctement disponibles sur les objets nouvellement créés et persistants (Doctrine ne reviendra pas à la base de données après avoir persisté un nouvel objet pour obtenir les valeurs par défaut).
<?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
.
options={"default": 0}
attention à utiliser "et non", car cela provoque des erreurs dans ma version de la doctrine.
Configurez un constructeur dans votre entité et définissez-y la valeur par défaut.
Utilisation:
options={"default":"foo bar"}
et pas:
options={"default"="foo bar"}
Par exemple:
/**
* @ORM\Column(name="foo", type="smallint", options={"default":0})
*/
private $foo
Une raison de plus pour laquelle la lecture de la documentation de Symfony ne sortira jamais de la tendance. Il existe une solution simple pour mon cas spécifique et consiste à définir l' field type
option empty_data
sur une valeur par défaut.
Encore une fois, cette solution est uniquement pour le scénario où une entrée vide dans un formulaire définit le champ DB sur null.
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:
J'ai ensuite essayé toutes les recommandations données ici. Permettez-moi de les énumérer:
<?php
/**
* @Entity
*/
class myEntity {
/**
* @var string
*
* @Column(name="myColumn", type="string", length="50")
*/
private $myColumn = 'myDefaultValue';
...
}
@ORM\Column(name="foo", options={"default":"foo bar"})
/**
* @Entity
*/
class myEntity {
...
public function __construct()
{
$this->myColumn = 'myDefaultValue';
}
...
}
Rien de tout cela n'a fonctionné et tout cela à cause de la façon dont Symfony utilise votre classe Entity.
Les champs de formulaire Symfony remplacent les valeurs par défaut définies sur 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, l' form->handleRequest()
intérieur de votre form->isValid()
méthode remplacera ces valeurs par défaut sur votre Entity
classe et les définira sur les valeurs du champ d'entrée. Si les valeurs du champ de saisie sont vides, il définira la Entity
propriété sur null
.
http://symfony.com/doc/current/book/forms.html#handling-form-submissions
Définissez la valeur par défaut sur votre contrôleur après l' form->handleRequest()
intérieur de votre form->isValid()
méthode:
...
if ($myEntity->getMyColumn() === null) {
$myEntity->setMyColumn('myDefaultValue');
}
...
Pas une belle solution mais ça marche. Je pourrais probablement faire un validation group
mais il peut y avoir des gens qui voient ce problème comme une transformation de données plutôt que la validation de données , je vous laisse le soin de décider.
J'ai également essayé de remplacer le Entity
setter de cette façon:
...
/**
* Set myColumn
*
* @param string $myColumn
*
* @return myEntity
*/
public function setMyColumn($myColumn)
{
$this->myColumn = ($myColumn === null || $myColumn === '') ? 'myDefaultValue' : $myColumn;
return $this;
}
...
Cela, même s'il semble plus propre, cela ne fonctionne pas . La raison étant que la mauvaise form->handleRequest()
méthode n'utilise pas les méthodes de définition du modèle pour mettre à jour les données (fouillez form->setData()
pour plus de détails).
La solution de contournement que j'ai utilisée était a LifeCycleCallback
. J'attends toujours de voir s'il y a plus de 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');
}
if (!$this->getDtPosted()) { $this->setDtPosted(new \DateTime()); }
Vous pouvez également 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>
Voici comment je l'ai résolu par moi-même. Voici 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 pour que vous puissiez y définir la valeur par défaut.
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'
columnDefinition
va directement contre le but d'avoir un ORM, qui est l'abstraction de la base de données. Cette solution rompra la portabilité, gardera votre logiciel dépendant de votre fournisseur de base de données et cassera également les outils de Doctrine Migrations.
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
Rien de tout cela n'a fonctionné pour moi. J'ai trouvé de la documentation sur le site de doctrine qui dit de définir la valeur directement pour définir une valeur par défaut.
private $default = 0;
Cela a inséré la valeur que je voulais.
Ajout à @romanb brillante réponse.
Cela ajoute un peu de surcharge dans la migration, car vous ne pouvez évidemment pas créer un champ sans contrainte 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 avez-vous 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.
Si vous utilisez la définition yaml pour votre entité, ce qui suit fonctionne 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
$entity->setFieldName()
avant de rincer? La doctrine semble définir la valeur par défaut à null. La seule solution dans yaml est de définir la valeur par défaut IN dans la classe d'entité qui me semble idiote puisqu'elle est déjà définie dans le yaml ... -_-
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";
Bien que la définition de la valeur dans le constructeur fonctionne, l'utilisation des événements Doctrine Lifecycle pourrait être une meilleure solution.
En tirant parti de l' prePersist
événement Cycle de vie, vous pouvez définir votre valeur par défaut sur votre entité uniquement lors de la persistance initiale.
hack
. Ne comptez jamais sur les hacks.
Soyez prudent lorsque vous définissez des valeurs par défaut sur la définition de propriété! Faites-le dans le constructeur à la place, pour le garder sans problème. Si vous le définissez lors de la définition de la propriété, puis conservez l'objet dans la base de données, puis effectuez un chargement partiel, les propriétés non chargées auront à nouveau la valeur par défaut. C'est dangereux si vous voulez à nouveau persister l'objet.