Значение по умолчанию в доктрине

338

Как установить значение по умолчанию в Doctrine 2?

Jiew Meng
источник
26
@ORM \ Column (name = "foo", type = "decimal", точность = 7, scale = 2, options = {"default" = 0}) работает (из непопулярного ответа ниже)
WayFarer
2
@ORM \ Column (name = "is_activation", type = "boolean", options = {"default": 0}) ИЛИ @ORM \ Column (name = "is_activation", type = "boolean", options = {"default "= 0})
Ахмед Хамди
Ахмед, похоже, это не работает для логических значений в Symfony 2.3. Однако options = {"default" = "0"}) работает, помещая целое число в кавычки.
Acyra
4
Если это логическое значение, почему вы не используете: options = {"default": false}?
Робокодер

Ответы:

385

Значения по умолчанию для базы данных не поддерживаются. Единственный способ использовать значения по умолчанию для базы данных - использовать columnDefinitionатрибут сопоставления, в котором вы указываете SQLфрагмент ( DEFAULTвключающий причину) для столбца, в который отображается поле.

Ты можешь использовать:

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

Значения по умолчанию на уровне PHP предпочтительнее, поскольку они также правильно доступны для вновь создаваемых и сохраняемых объектов (Doctrine не вернется в базу данных после сохранения нового объекта для получения значений по умолчанию).

RomanB
источник
11
но здесь есть проблема: что если я установлю тип "datetime"?
Artragis
46
@artragis поместил ваше воплощение в конструктор сущностей
Ален Тьембло,
16
При использовании этого подхода необходимо соблюдать осторожность, так как любые существующие строки приведут к сбою миграции.
Тамлин
7
Не используйте область инстанцирования для установки переменных ... Поверьте мне, случится плохое. Вместо этого используйте область конструктора.
Mimoralea
4
Я рекомендую использовать columnDefinition в аннотации, или кто-то будет использовать клиент MySQL или phpmyadmin, и значения будут неправильными ...
NDM
542
<?php
/**
 * @Entity
 */
class myEntity {
    /**
     * @var string
     *
     * @ORM\Column(name="myColumn", type="integer", options={"default" : 0})
     */
    private $myColumn;
    ...
}

Обратите внимание, что здесь используется SQL DEFAULT, который не поддерживается для некоторых полей, таких как BLOBи TEXT.

iv3ndy
источник
4
Хороший улов! Кажется, в официальной документации нет опции options = {"default" = 0}
WayFarer
2
К вашему сведению, этот optionsпараметр также полезен для unsignedзначений. см. этот ответ
yvoyer
5
Я использую и этот, и принятый ответ, чтобы охватить все основы. Также просто примечание, которое вы также можете сделать: options={"default": 0}будьте осторожны, используя «а не», так как это вызывает ошибки в моей версии доктрины.
Скотт Флэк,
28
Это должен быть выбранный ответ!
Acelasi Eu
2
@Matt он, вероятно, сказал, что, поскольку это была недокументированная функция, и недокументированные функции могут быть удалены. Как сейчас задокументировано, вы должны быть в безопасности, используя его.
JCM
62

Установите конструктор в вашей сущности и установите там значение по умолчанию.

Джереми Хикс
источник
Это, конечно, кажется логичным подходом. Кто-нибудь сталкивался с проблемами с настройкой по умолчанию в конструкторе?
cantera
26
Рекомендуемое решение Доктрины: doctrine-project.org/docs/orm/2.1/en/reference/faq.html
cantera
@ cantera25, это должен быть ответ +1
Фил Паффорд
3
это не обновляет существующие объекты, если вы добавляете новое поле, которое должно иметь значение по умолчанию. так что нет, это не должно быть ответом. зависит от того, что именно вам нужно сделать
Томаш Тибенский
Это не будет работать в целях обновления либо. Если вы хотите вернуться к значению по умолчанию, просто очистив поле (даже для целого числа), к сожалению, это не сработает.
TheBiShOp
55

Использование:

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

и нет:

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

Например:

/**
* @ORM\Column(name="foo", type="smallint", options={"default":0})
*/
private $foo
Станислав Терлецкий
источник
2
Извини, ты прав. Таким образом, вы можете найти объяснение на этой странице: аннотации к доктрине - ссылка
Станислав Терлецкий
51

Обновить

Еще одна причина, почему чтение документации для Symfony никогда не выйдет из моды. Существует простое решение для моего конкретного случая и установить field typeпараметр empty_dataв значение по умолчанию.

Опять же, это решение предназначено только для сценария, в котором пустой ввод в форме устанавливает для поля БД значение null.

Задний план

Ни один из предыдущих ответов не помог мне с моим конкретным сценарием, но я нашел решение.

У меня было поле формы, которое должно было вести себя следующим образом:

  1. Не требуется, можно оставить пустым. (Используется 'обязательный' => ложь)
  2. Если оставить это поле пустым, по умолчанию должно быть задано значение. Для удобства пользователей я не устанавливал значение по умолчанию в поле ввода, а использовал атрибут html «заполнитель», поскольку он менее навязчив.

Затем я попробовал все рекомендации, приведенные здесь. Позвольте мне перечислить их:

  • Установите значение по умолчанию, когда для свойства объекта:
<?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';
    }
    ...
}
Ничего из этого не сработало, и все из-за того, как Symfony использует ваш класс Entity.

ВАЖНЫЙ

Поля формы Symfony переопределяют значения по умолчанию, заданные в классе Entity. Это означает, что в вашей схеме для вашей БД может быть определено значение по умолчанию, но если вы оставите необязательное поле пустым при отправке формы, form->handleRequest()внутри вашего form->isValid()метода будет переопределен этот стандарт по умолчанию в вашем Entityклассе и задан для значений поля ввода. Если значения поля ввода не заполнены, тогда для Entityсвойства будет установлено значение null.

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

Мой обходной путь

Установите значение по умолчанию на вашем контроллере после form->handleRequest()внутри вашего form->isValid()метода:

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

Не красивое решение, но оно работает. Я мог бы сделать, validation groupно могут быть люди, которые рассматривают эту проблему как преобразование данных, а не проверку данных , я оставляю вам решать.


Переопределить сеттер (не работает)

Я также попытался переопределить Entityсеттер следующим образом:

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

    return $this;
}
...

Это, хотя это выглядит чище, но не работает . Причина в том, что злой form->handleRequest()метод не использует методы установки Модели для обновления данных (изучите form->setData()более подробно).

Callistino
источник
Этот ответ должен идти в топ наверняка. Компонент формы использует PropertyAccessor для получения и установки значений для ваших свойств. Может быть, средство доступа к свойствам должно использовать методы, когда они доступны?
Xobb
1
логические столбцы не поддерживают значения по умолчанию от php, поэтому только аннотации
Crusader
Это единственное решение, которое работает, когда информация поступает из форм. Также я не согласен с вышеупомянутыми комментариями относительно логического значения. Они не принимают аннотацию по умолчанию.
Бернарда
Компонент формы Symfony использует установщики моделей, но только в том случае, если данные формата модели в форме отличаются от данных, возвращаемых соответствующим получателем экземпляра объекта модели. Если у вас есть пользовательские методы установки / получения - используйте параметр формы «property_path» (будет обрабатываться PropertyAccessor) или пользовательский DataMapper (позволяет вручную определять процедуру передачи данных между формой и объектом модели).
Arkemlar
1
Этот вопрос касается доктрины, а не symfony, так что этот ответ на самом деле не по теме.
Omn
18

Обходной путь, который я использовал, был LifeCycleCallback. Все еще жду, чтобы увидеть, например, есть ли еще «родной» метод @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');
}
Jiew Meng
источник
1
Для будущих читателей не полагайтесь на обратные вызовы жизненного цикла :), даже Марко Пиветта против них.
emix
Предупреждение! Если объект уже установил свойство dtPosted, то ваш код просто перезапишет свойство. Всегда используйте аксессоры, если они существуют! if (!$this->getDtPosted()) { $this->setDtPosted(new \DateTime()); }
Барх
13

Вы можете сделать это, используя 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>
Андрей Жилин
источник
8

Вот как я решил это для себя. Ниже приведен пример Entity со значением по умолчанию для MySQL. Тем не менее, это также требует настройки конструктора в вашей сущности, и для вас, чтобы установить значение по умолчанию там.

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'
Путна
источник
С этой строкой в ​​моем конфиге Doctrine пытается сбросить значение по умолчанию для столбца при каждом запуске. php app / console доктрина: schema: update
shapehifter
1
Это худший ответ здесь. columnDefinitionидет прямо против цели наличия ORM, который является абстракцией от базы данных. Это решение нарушит мобильность, сохранит зависимость вашего программного обеспечения от поставщика БД, а также сломает инструменты Doctrine Migrations.
Педро Кордейру
@PedroCordeiro Я полностью согласен с вами. Это просто быстрое решение, пока не возникнет другая проблема.
Путна
7

У меня работает и в базе данных mysql:

Entity\Entity_name:
    type: entity
    table: table_name
    fields: 
        field_name:
            type: integer
            nullable: true
            options:
                default: 1
Алекс Хоанг
источник
В формате аннотации, для которого это интересно: @ORM \ Column (name = "Entity_name", type = "integer", options = {"default" = "1"})
Ханнес
7

Ничто из этого не сработало для меня. Я нашел некоторую документацию на сайте доктрины, в которой говорится, чтобы установить значение напрямую, чтобы установить значение по умолчанию.

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;

Это вставило значение, которое я хотел.

metric152
источник
Пожалуйста, измените ссылку на doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/… См. Пункт 3.2.2. Как добавить значения по умолчанию в столбец?
Тоби
3

Добавление в @romanb блестящий ответ.

Это добавляет немного накладных расходов при миграции, потому что вы, очевидно, не можете создать поле с ненулевым ограничением и без значения по умолчанию.

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

С этим ответом я призываю вас задуматься, зачем вам сначала значение по умолчанию в базе данных? И обычно это позволяет создавать объекты с ненулевым ограничением.

Dziamid
источник
3

Если вы используете определение yaml для своей сущности, для меня работает следующее в базе данных postgresql:

Entity\Entity_name:
    type: entity
    table: table_name
    fields: 
        field_name:
            type: boolean
            nullable: false
            options:
                default: false
wonzbak
источник
1
Что делать, если вы не использовали $entity->setFieldName()перед промывкой? Doctrine, похоже, определяет значение по умолчанию в null. Единственное решение в yaml - определить значение по умолчанию В классе сущностей, которое мне кажется глупым, поскольку оно уже определено в yaml ... -_-
j0k
1

Я боролся с той же проблемой. Я хотел получить значение по умолчанию из базы данных в сущности (автоматически). Угадай что, я сделал это :)

<?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";
Штеффен Брем
источник
3
Возвращаясь к этому через несколько лет, я рекомендую вам не использовать этот подход, это действительно хакерский взлом.
Штеффен Брем
Так как вы не рекомендуете свой собственный ответ, вы также можете удалить его;)
Dragos
1

Хотя установка значения в конструкторе будет работать, лучше использовать события жизненного цикла Doctrine.

Используя prePersistсобытие жизненного цикла, вы можете установить значение по умолчанию для вашей сущности только при первоначальном сохранении.

tiruncula
источник
Использование событий жизненного цикла считается hack. Никогда не полагайтесь на хаки.
emix
0

Будьте осторожны при установке значений по умолчанию при определении свойства! Вместо этого сделайте это в конструкторе, чтобы сохранить его без проблем. Если вы определите его в определении свойства, затем сохраните объект в базе данных, затем выполните частичную загрузку, тогда незагруженные свойства снова будут иметь значение по умолчанию. Это опасно, если вы хотите сохранить объект снова.

tomazahlin
источник