356

How do I set a default value in Doctrine 2?

Nathaniel Ford
  • 16,853
  • 18
  • 74
  • 88
Jiew Meng
  • 74,635
  • 166
  • 442
  • 756
  • 27
    @ORM\Column(name="foo", type="decimal", precision=7, scale=2, options={"default" = 0}) works (from the non-popular answer below) – WayFarer Aug 21 '12 at 14:01
  • 3
    @ORM\Column(name="is_activated", type="boolean",options={"default":0}) OR @ORM\Column(name="is_activated", type="boolean",options={"default"= 0}) – ahmed hamdy Nov 19 '13 at 15:10
  • Ahmed this doesn't seem to work for booleans in Symfony 2.3. However options={"default" = "0"}) does work, putting the integer in quotes. – Acyra Mar 07 '14 at 15:23
  • 4
    If it's a boolean, why aren't you using: options={"default":false} ? – robocoder Oct 12 '17 at 16:36

15 Answers15

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

Note that this uses SQL DEFAULT, which is not supported for some fields like BLOB and TEXT.

darckcrystale
  • 1,090
  • 12
  • 31
iv3ndy
  • 6,031
  • 1
  • 10
  • 3
  • 4
    Good catch! It seems there are no options={"default" = 0} option in official documentation – WayFarer Aug 21 '12 at 13:57
  • 2
    FYI, the `options` parameter is also useful for `unsigned` values. see this [answer](http://stackoverflow.com/questions/7692686/doctrine-2-unsigned-value/14221973#14221973) – yvoyer Jan 08 '13 at 18:55
  • Very nice! This is very useful _in addition_ to having defaults in PHP (as per the accepted answer) when you are migrating between model versions and don't want pre-existing entities to get a null value for a newly-added field! – Ezequiel Muns Apr 17 '13 at 05:40
  • 1
    Does not support booleans. Also, may disappear in further Doctrine versions. – wdev Jul 02 '13 at 12:49
  • 1
    @wdev it supports booleans just fine with Doctrine 2.4 on Postgresql 8+ – ChrisR Dec 18 '13 at 09:22
  • 5
    I use both this and the accepted answer to cover all bases. Also just a note that you can also do: `options={"default": 0}` Be careful to use " and not ', as it causes errors in my version of doctrine. – Scott Flack Jun 17 '14 at 07:37
  • 35
    This should be the selected answer! – Acelasi Eu Sep 23 '14 at 20:22
  • @wdev as of 2015 (two years after your comment, it is now in the documentation [1]. However, your comment worries me. Do you know if it is actually slated for removal or did you base that on the fact that it was not in the docs at the time? [1]:http://doctrine-orm.readthedocs.org/en/latest/reference/annotations-reference.html#annref-column – Matt Sep 19 '15 at 09:42
  • 2
    @Matt he probably said that because it was an undocumented feature, and undocummented features are prone to being removed. As it's documented now, you should be safe using it. – jonathancardoso Nov 01 '15 at 18:50
  • 3
    When working with migrations, this is definitely the desired solution, as otherwise a `doctrine:migrations:diff` will not understand that you have set a default value, since that only scans the annotation/metadata and not the PHP defaults. – Oldskool Aug 16 '16 at 15:43
  • This solution given by @iv3ndy is nicely working. After implementing it to add a default value 1 for a boolean entity property and when I checked the generated migration file, this line was added: $this->addSql('ALTER TABLE user CHANGE is_active is_active TINYINT(1) DEFAULT \'1\' NOT NULL'); Prior to this, any time I tweaked the migration file, all manually injected changes into migration file were asked to be reverted, of course because the entity file was still intact. But now, all is fine. :) – Ali May 05 '20 at 05:07
403

Database default values are not "portably" supported. The only way to use database default values is through the columnDefinition mapping attribute where you specify the SQL snippet (DEFAULT cause inclusive) for the column the field is mapped to.

You can use:

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

PHP-level default values are preferred as these are also properly available on newly created and persisted objects (Doctrine will not go back to the database after persisting a new object to get the default values).

fotanus
  • 18,299
  • 11
  • 71
  • 106
romanb
  • 6,123
  • 2
  • 18
  • 19
  • 11
    but there is a problem here : What if I set a "datetime" type? – artragis Sep 11 '12 at 09:04
  • 47
    @artragis put your instanciation in the entity constructor – Alain Tiemblo Sep 29 '12 at 17:52
  • 18
    Care has to be taken with migrations using this approach as any existing rows will cause the migration to fail. – Tamlyn Oct 29 '13 at 14:44
  • @Tamlyn Do you mean that if you add a new column, the migration won't set this default value to the pre-existing rows, or something else? I think it's always sensible to set the value of a new column manually in your migration, unless they want to be null. It's possible existing rows will want a special value, not the default value for new rows. – rjmunro Feb 14 '14 at 14:23
  • @Tamlyn, @rjmunro, so when migrating, I noticed that if I add field which is `nullable=true` then it will obviously `NULL` in the updated DB once `doctrine:schema:update` is called (which is the expected behaviour). Whereas if the field added is 'nullable=false` then integer(ish) column values will be initialized to `0`. Didn't try yet `varchar`. And looks like upon `schema:update` I actually need to call separate script, which will process all rows and set valid value for the field. Any other advice on migration, guys? – Dimitry K Jun 11 '14 at 08:29
  • On an update, if you do not include the saved/original value for that field, it will always get overwritten with the class variable (default) – Eddie Jaoude Jun 18 '14 at 14:21
  • 7
    Do not use the instantiation area to set variables... Trust me, bad thing will happen. Use the constructor area instead. – mimoralea Sep 04 '14 at 15:08
  • 4
    I reccomend to use the columnDefinition in the annotation, or somebody will use the mysql client or phpmyadmin and the values will be wrong... – NDM May 04 '15 at 14:09
  • IMHO that isn´t a default value - just an initial. If you edit an entity and add a new column and want to set a default value, it won´t be set to the old entries, just to the new ones. So, the answer from iv3ndy is the correct one, if you want a really default value – develth Aug 10 '16 at 14:10
  • 2
    you also need to do , options={"default" : 0} if you don't want to fuck up your migrations on a not-nullable field – H.Molnar Apr 03 '19 at 09:37
64

Set up a constructor in your entity and set the default value there.

Jeremy Hicks
  • 3,640
  • 5
  • 38
  • 48
  • This certainly seems like the logical approach. Has anyone run into issues with setting up defaults in the constructor? – cantera Nov 01 '11 at 11:16
  • 26
    Doctrine's recommended solution: http://www.doctrine-project.org/docs/orm/2.1/en/reference/faq.html – cantera Nov 01 '11 at 11:16
  • @cantera25 that should be the answer +1 – Phill Pafford Dec 12 '12 at 21:17
  • 4
    this doesn't update existing entities if you add new field which needs to have default value. so no that shouldn't be the answer. depends on what exactly you need to do – Tomáš Tibenský May 04 '16 at 12:07
  • It won't work on update purpose either. If you want to go back to the default value by just emptying the field (even for integer), unfortunately, it won't work. – ThEBiShOp Sep 20 '16 at 08:18
  • 3
    New link to the FAQ on that topic: https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/faq.html#entity-classes – Calamity Jane Nov 06 '19 at 10:42
57

Use:

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

and not:

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

For instance:

/**
* @ORM\Column(name="foo", type="smallint", options={"default":0})
*/
private $foo
Prasad Jadhav
  • 4,786
  • 16
  • 57
  • 79
Stanislav Terletskyi
  • 1,814
  • 18
  • 16
  • 2
    I'm sorry, you are right. So you can find an explanation on this page: [doctrine-orm annotations-reference](http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/reference/annotations-reference.html#column) – Stanislav Terletskyi May 26 '16 at 12:27
  • 1
    The link in the above comment is dead. Try [this one](https://www.doctrine-project.org/projects/doctrine-orm/en/2.8/reference/annotations-reference.html#column). – naitsirch Jan 21 '21 at 07:57
57

Update

One more reason why read the documentation for Symfony will never go out of trend. There is a simple solution for my specific case and is to set the field type option empty_data to a default value.

Again, this solution is only for the scenario where an empty input in a form sets the DB field to null.

Background

None of the previous answers helped me with my specific scenario but I found a solution.

I had a form field that needed to behave as follow:

  1. Not required, could be left blank. (Used 'required' => false)
  2. If left blank, it should default to a given value. For better user experience, I did not set the default value on the input field but rather used the html attribute 'placeholder' since it is less obtrusive.

I then tried all the recommendations given in here. Let me list them:

  • Set a default value when for the entity property:
<?php
/**
 * @Entity
 */
class myEntity {
    /**
     * @var string
     *
     * @Column(name="myColumn", type="string", length="50")
     */
    private $myColumn = 'myDefaultValue';
    ...
}
  • Use the options annotation:
@ORM\Column(name="foo", options={"default":"foo bar"})
  • Set the default value on the constructor:
/**
 * @Entity
 */
class myEntity {
    ...
    public function __construct()
    {
        $this->myColumn = 'myDefaultValue';
    }
    ...
}
None of it worked and all because of how Symfony uses your Entity class.

IMPORTANT

Symfony form fields override default values set on the Entity class. Meaning, your schema for your DB can have a default value defined but if you leave a non-required field empty when submitting your form, the form->handleRequest() inside your form->isValid() method will override those default values on your Entity class and set them to the input field values. If the input field values are blank, then it will set the Entity property to null.

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

My Workaround

Set the default value on your controller after form->handleRequest() inside your form->isValid() method:

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

Not a beautiful solution but it works. I could probably make a validation group but there may be people that see this issue as a data transformation rather than data validation, I leave it to you to decide.


Override Setter (Does Not Work)

I also tried to override the Entity setter this way:

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

    return $this;
}
...

This, even though it looks cleaner, it doesn't work. The reason being that the evil form->handleRequest() method does not use the Model's setter methods to update the data (dig into form->setData() for more details).

Geoffrey Hale
  • 8,152
  • 4
  • 34
  • 42
Callistino
  • 1,015
  • 11
  • 13
  • This answer should go to the top for sure. Form component uses PropertyAccessor to get and set the values for your properties. Maybe the property accessor should use the methods when they are available? – Xobb Aug 11 '14 at 13:36
  • 1
    boolean columns don`t support defaults from php, so only annotations – Crusader Dec 05 '16 at 08:34
  • This is the only solution that worked when info is coming from forms. Also I disagree with above comments concerning boolean. They do not accept the default annotation. – BernardA Nov 01 '17 at 10:00
  • Symfony form component **uses** model setters but only when _model format_ data of the form differs with data returned by corresponding getter of model object instance. If you have your custom setter/getter methods - use "property_path" form option (will be handled by PropertyAccessor) or custom DataMapper (allows to manually define data transfer routine between form and model object). – Arkemlar Nov 02 '17 at 16:36
  • 1
    This question is about doctrine, not symfony, so this answer isn't really on topic. – Omn Oct 03 '19 at 20:34
  • I created Custom Enum Type, set default option this way: `@ORM\Column(type="statusVisibility", nullable=true, options={"default": StatusVisibilityType::DEFAULT_VALUE})`. it generated following Migration code:`ALTER TABLE status ADD visibility ENUM('ADMIN', 'USER', 'PUBLIC') DEFAULT 'ADMIN' COMMENT '(DC2Type:statusVisibility)'` – Nuryagdy Mustapayev Jun 26 '20 at 16:37
18

The workaround I used was a LifeCycleCallback. Still waiting to see if there is any more "native" method, for instance @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');
}
Nathaniel Ford
  • 16,853
  • 18
  • 74
  • 88
Jiew Meng
  • 74,635
  • 166
  • 442
  • 756
  • 3
    For future readers, don't rely on lifecycle callbacks :) even Marco Pivetta is against them. – emix Mar 09 '19 at 14:57
  • Warning! If the Entity has already set the dtPosted property, then your code will simply overwrite the property. Always use accessors if they exist! `if (!$this->getDtPosted()) { $this->setDtPosted(new \DateTime()); }` – Maxim Mandrik Mar 29 '19 at 21:33
  • @emix can you explain? – Erdal G. Dec 03 '20 at 20:29
14

You can do it using xml as well:

<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>
Andrew Zhilin
  • 911
  • 9
  • 9
8

Here is how I solved it for myself. Below is an Entity example with default value for MySQL. However, this also requires the setup of a constructor in your entity, and for you to set the default value there.

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'
Nathaniel Ford
  • 16,853
  • 18
  • 74
  • 88
Putna
  • 865
  • 1
  • 8
  • 5
  • 1
    With this line in my config Doctrine tries to drop the default on the column everytime I run. php app/console doctrine:schema:update – shapeshifter Jun 03 '13 at 00:27
  • 1
    This is the worst answer here. `columnDefinition` goes directly agains the purpose of having an ORM, which is abstraction from the database. This solution will break portability, will keep your software dependant on your DB vendor and will also break Doctrine Migrations tools. – Pedro Cordeiro Feb 25 '14 at 14:30
  • @PedroCordeiro I completely agree with you. This is just a fast solution until another issue rises. – Putna Feb 27 '14 at 15:40
7

Works for me on a mysql database also:

Entity\Entity_name:
    type: entity
    table: table_name
    fields: 
        field_name:
            type: integer
            nullable: true
            options:
                default: 1
Nathaniel Ford
  • 16,853
  • 18
  • 74
  • 88
Alex Hoang
  • 171
  • 2
  • 3
  • In annotation format for whom is interested: @ORM\Column(name="Entity_name", type="integer", options={"default"="1"}) – Hannes May 03 '16 at 07:16
7

None of this worked for me. I found some documentation on doctrine's site that says to set the value directly to set a default value.

https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/faq.html#how-can-i-add-default-values-to-a-column

private $default = 0;

This inserted the value I wanted.

Manuel
  • 787
  • 11
  • 30
metric152
  • 362
  • 2
  • 16
  • Please change the link to http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/reference/faq.html See Point 3.2.2. How can I add default values to a column? – Tobi May 10 '16 at 08:16
  • Correct link: [Doctrine v.2.6. Reference. FAQ. How can I add default values to a column?](https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/faq.html#how-can-i-add-default-values-to-a-column) – Maxim Mandrik Mar 29 '19 at 21:02
3

Adding to @romanb brilliant answer.

This adds a little overhead in migration, because you obviously cannot create a field with not null constraint and with no default value.

// 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");

With this answer, I encourage you to think why do you need the default value in the database in the first place? And usually it is to allow creating objects with not null constraint.

Brais Gabin
  • 5,447
  • 5
  • 50
  • 88
Dziamid
  • 10,081
  • 11
  • 62
  • 100
3

If you use yaml definition for your entity, the following works for me on a postgresql database:

Entity\Entity_name:
    type: entity
    table: table_name
    fields: 
        field_name:
            type: boolean
            nullable: false
            options:
                default: false
wonzbak
  • 6,128
  • 6
  • 23
  • 24
  • 1
    What if you didn't use `$entity->setFieldName()` before flushing? Doctrine seems to define the default value at null. The only solution in yaml is to define the default value *IN* the entity class which seems dumb to me since it's already defined in the yaml ... -_- – j0k Mar 10 '15 at 13:42
1

While setting the value in the constructor would work, using the Doctrine Lifecycle events might be a better solution.

By leveraging the prePersist Lifecycle Event, you could set your default value on your entity only on initial persist.

Nathaniel Ford
  • 16,853
  • 18
  • 74
  • 88
tiruncula
  • 151
  • 2
  • 5
0

I struggled with the same problem. I wanted to have the default value from the database into the entities (automatically). Guess what, I did it :)

<?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";
Steffen Brem
  • 1,662
  • 17
  • 26
0

Be careful when setting default values on property definition! Do it in constructor instead, to keep it problem-free. If you define it on property definition, then persist the object to the database, then make a partial load, then not loaded properties will again have the default value. That is dangerous if you want to persist the object again.

tomazahlin
  • 1,992
  • 1
  • 21
  • 29