Значення за замовчуванням у Doctrine


338

Як встановити значення за замовчуванням у Doctrine 2?


26
@ORM \ Стовпець (name = "foo", type = "decimal", точність = 7, шкала = 2, параметри = {"за замовчуванням" = 0}) працює (з не популярної відповіді нижче)
WayFarer

2
@ORM \ Column (name = "is_activate", type = "boolean", options = {"default": 0}) OR @ORM \ Column (name = "is_activate", type = "boolean", options = {"за замовчуванням "= 0})
ахмед хамді

Ахмед, схоже, не працює для булів у Symfony 2.3. Однак options = {"default" = "0"}) працює, ставлячи ціле число в лапки.
Акіра

4
Якщо це булевий, чому ви не використовуєте: options = {"default": false}?
robocoder

Відповіді:


385

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

Ви можете використовувати:

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

Значення за замовчуванням на рівні PHP є кращими, оскільки вони також належним чином доступні для новостворених та збережених об'єктів (Доктрина не повернеться до бази даних після збереження нового об’єкта для отримання значень за замовчуванням).


11
але тут є проблема: що робити, якщо я встановив тип "datetime"?
artragis

46
@artragis поставив вашу інстанцію в конструкторі сутності
Ален Тімбло

16
Слід бути обережним із міграціями, використовуючи цей підхід, оскільки будь-які існуючі рядки можуть призвести до збою міграції.
Тамлін

7
Не використовуйте область інстанцій для встановлення змінних ... Повірте, трапиться погана річ. Замість цього використовуйте область конструктора.
mimoralea

4
Я рекомендую використовувати колонкуDefinition в анотації, або хтось буде користуватися клієнтом 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.


4
Гарний улов! Здається, немає опцій = {"за замовчуванням" = 0} варіант в офіційній документації
WayFarer

2
FYI, optionsпараметр також корисний для unsignedзначень. дивіться цю відповідь
yvoyer

5
Я використовую і це, і прийняту відповідь, щоб охопити всі основи. Також лише зауваження, яке ви також можете зробити: options={"default": 0}будьте обережні, щоб використовувати "і ні", оскільки це спричиняє помилки в моїй версії доктрини.
Скотт Флак,

28
Це має бути обрана відповідь!
Ацеласі Єв

2
@Matt він, ймовірно, сказав, що це була недокументована функція, а недокументовані функції схильні до видалення. Як це зафіксовано зараз, ви повинні безпечно користуватися ним.
JCM

62

Налаштуйте конструктор у вашій сутності та встановіть там значення за замовчуванням.


Це, звичайно, здається логічним підходом. Хтось стикався з проблемами з налаштуванням за замовчуванням у конструкторі?
cantera

26
Рекомендоване рішення доктрини
cantera

@ cantera25, яка повинна відповісти +1
Філл Паффорд

3
це не оновлює існуючі об'єкти, якщо ви додасте нове поле, яке має мати значення за замовчуванням. тож ні, це не повинно бути відповіддю. залежить від того, що саме вам потрібно зробити
Tomáš Tibenský

Він також не працюватиме з метою оновлення. Якщо ви хочете повернутися до значення за замовчуванням, просто випорожнивши поле (навіть для цілого числа), на жаль, воно не вийде.
THEBiShOp


51

Оновлення

Ще одна причина, чому читати документацію для Symfony ніколи не вийде з тренду. Існує просте рішення для мого конкретного випадку і полягає у встановленні для field typeпараметра empty_dataзначення за замовчуванням.

Знову ж таки, це рішення є лише для сценарію, коли порожнє введення у формі встановлює нульове поле БД.

Фон

Жодна з попередніх відповідей не допомогла мені в конкретному сценарії, але я знайшов рішення.

У мене було поле форми, яке потрібно було поводити так:

  1. Не потрібно, його можна залишити порожнім. (Використовується 'обов'язково' => помилково)
  2. Якщо залишити порожнім, воно повинно бути за замовчуванням заданим значенням. Для кращого досвіду користувача я не встановлював значення за замовчуванням у полі введення, а скоріше використовував атрибут html 'placeholder', оскільки він менш нав'язливий.

Потім я спробував усі рекомендації, наведені тут. Дозвольте мені перерахувати їх:

  • Встановіть значення за замовчуванням, коли для властивості сутності:
<?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()перегляньте детальніше).


Ця відповідь повинна точно перейти до вершини. Компонент форми використовує PropertyAccessor для отримання та встановлення значень для ваших властивостей. Може, користувач власності повинен використовувати методи, коли вони доступні?
Xobb

1
булеві стовпці не підтримують налаштування за замовчуванням від php, тому лише анотації
хрестоносців

Це єдине рішення, яке працювало, коли інформація надходить із форм. Також я не згоден з вищезазначеними коментарями щодо булевих. Вони не приймають анотацію за замовчуванням.
Бернарда

Компонент форми Symfony використовує задачі моделі, але лише тоді, коли дані формату моделі відрізняються від даних, повернутих відповідним отримувачем екземпляра модельного об'єкта. Якщо у вас є власні методи налаштування / отримання, використовуйте параметр форми "property_path" (буде оброблятися PropertyAccessor) або користувацький DataMapper (дозволяє вручну визначити процедуру передачі даних між формою та об'єктом моделі).
Arkemlar

1
Це питання стосується доктрини, а не симфонії, тому ця відповідь насправді не є темою.
Омн

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');
}

1
Для майбутніх читачів не варто покладатися на зворотні дзвінки життєвого циклу :) навіть Марко Піветта проти них.
emix

Увага! Якщо Entity вже встановила властивість 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: схема: оновлення
shapehifter

1
Тут найгірша відповідь. columnDefinitionйде безпосередньо до мети створення ORM, яка є абстрагуванням від бази даних. Це рішення порушить портативність, забезпечить залежність вашого програмного забезпечення від постачальника даних DB, а також порушить інструменти міграції доктрин.
Педро Кордейро,

@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"})
Hannes

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;

Це вставило потрібне мені значення.


Будь ласка, змініть посилання на 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");

Відповідаючи на цю відповідь, я закликаю вас подумати, навіщо в першу чергу вам потрібне значення за замовчуванням у базі даних? І, як правило, це дозволяє створювати об'єкти з ненульовим обмеженням.


3

Якщо ви використовуєте визначення yaml для своєї організації, для мене в базі даних postgresql працює наступне:

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

1
Що робити, якщо ви не користувалися $entity->setFieldName()перед промиванням? Здається, доктрина визначає значення за замовчуванням у null. Єдине рішення в yaml - це визначити значення за замовчуванням IN -класу сутності, яке здається мені німим, оскільки воно вже визначене в 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

Хоча встановлення значення в конструкторі спрацює, кращим рішенням може бути використання подій життєвого циклу доктрини.

Використовуючи prePersistподію життєвого циклу, ви можете встановити значення за замовчуванням для вашої сутності лише на первісному збереженні.


Використання подій життєвого циклу вважається а hack. Ніколи не покладайтеся на хаків.
емікс

0

Будьте уважні, встановлюючи значення за замовчуванням для визначення властивості! Зробіть це замість цього в конструкторі, щоб зберегти його без проблем. Якщо ви визначите його за визначенням властивості, то збережіть об'єкт у базі даних, потім зробіть часткове завантаження, тоді не завантажені властивості знову матимуть значення за замовчуванням. Це небезпечно, якщо ви хочете знову зберегти об'єкт.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.