Nilai default dalam Ajaran

338

Bagaimana cara menetapkan nilai default di Ajaran 2?

Jiew Meng
sumber
26
@ORM \ Kolom (nama = "foo", ketik = "desimal", presisi = 7, skala = 2, opsi = {"default" = 0}) berfungsi (dari jawaban tidak populer di bawah ini)
WayFarer
2
@ORM \ Kolom (name = "is_activated", type = "boolean", options = {"default": 0}) ATAU @ORM \ Kolom (name = "is_activated", type = "boolean", options = {"default "= 0})
ahmed hamdy
Ahmed ini tampaknya tidak berfungsi untuk boolean di Symfony 2.3. Namun opsi = {"default" = "0"}) tidak berfungsi, menempatkan bilangan bulat dalam tanda kutip.
Acyra
4
Jika boolean, mengapa Anda tidak menggunakan: options = {"default": false}?
robocoder

Jawaban:

385

Nilai default basis data tidak didukung "portable". Satu-satunya cara untuk menggunakan nilai default basis data adalah melalui columnDefinitionatribut pemetaan tempat Anda menentukan SQLsnippet ( DEFAULTpenyebab inklusif) untuk kolom yang bidangnya dipetakan.

Kamu bisa memakai:

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

Nilai default tingkat PHP lebih disukai karena ini juga tersedia dengan benar pada objek yang baru dibuat dan bertahan (Doctrine tidak akan kembali ke database setelah mempertahankan objek baru untuk mendapatkan nilai default).

romanb
sumber
11
tetapi ada masalah di sini: Bagaimana jika saya menetapkan tipe "datetime"?
artragis
46
@artragis meletakkan instanciation Anda di konstruktor entitas
Alain Tiemblo
16
Perawatan harus diambil dengan migrasi menggunakan pendekatan ini karena setiap baris yang ada akan menyebabkan migrasi gagal.
Tamlyn
7
Jangan gunakan area instantiasi untuk mengatur variabel ... Percayalah, hal buruk akan terjadi. Gunakan area konstruktor sebagai gantinya.
mimoralea
4
Saya merekomendasikan untuk menggunakan kolomDefinisi dalam anotasi, atau seseorang akan menggunakan klien mysql atau phpmyadmin dan nilainya akan salah ...
NDM
542
<?php
/**
 * @Entity
 */
class myEntity {
    /**
     * @var string
     *
     * @ORM\Column(name="myColumn", type="integer", options={"default" : 0})
     */
    private $myColumn;
    ...
}

Perhatikan bahwa ini menggunakan SQL DEFAULT, yang tidak didukung untuk beberapa bidang seperti BLOBdan TEXT.

iv3ndy
sumber
4
Tangkapan yang bagus! Tampaknya tidak ada opsi = {"default" = 0} opsi dalam dokumentasi resmi
WayFarer
2
FYI, optionsparameter ini juga berguna untuk unsignednilai. lihat jawaban
yvoyer
5
Saya menggunakan ini dan jawaban yang diterima untuk mencakup semua pangkalan. Juga hanya sebuah catatan yang dapat Anda lakukan: options={"default": 0}Berhati-hatilah untuk menggunakan "dan tidak ', karena hal itu menyebabkan kesalahan dalam versi doktrin saya.
Scott Flack
28
Ini harus menjadi jawaban yang dipilih!
Acelasi Eu
2
@Matt dia mungkin mengatakan itu karena itu adalah fitur yang tidak berdokumen, dan fitur yang tidak terdokumentasi cenderung dihapus. Seperti yang sudah didokumentasikan sekarang, Anda harus aman menggunakannya.
JCM
62

Siapkan konstruktor di entitas Anda dan atur nilai default di sana.

Jeremy Hicks
sumber
Ini tentu saja tampak seperti pendekatan logis. Adakah yang mengalami masalah dengan pengaturan default di konstruktor?
cantera
26
Solusi yang disarankan Doctrine: doctrine-project.org/docs/orm/2.1/en/reference/faq.html
cantera
@ cantera25 yang seharusnya menjadi jawaban +1
Phill Pafford
3
ini tidak memperbarui entitas yang ada jika Anda menambahkan bidang baru yang perlu memiliki nilai default. jadi tidak seharusnya itu bukan jawabannya. tergantung pada apa yang sebenarnya perlu Anda lakukan
Tomáš Tibenský
Itu tidak akan berfungsi pada tujuan pembaruan juga. Jika Anda ingin kembali ke nilai default dengan hanya mengosongkan bidang (bahkan untuk integer), sayangnya, itu tidak akan berfungsi.
ThEBiShOp
55

Menggunakan:

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

dan tidak:

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

Misalnya:

/**
* @ORM\Column(name="foo", type="smallint", options={"default":0})
*/
private $foo
Stanislav Terletskyi
sumber
2
Maaf, kamu benar. Jadi Anda dapat menemukan penjelasan di halaman ini: referensi-orm annotations-reference
Stanislav Terletskyi
51

Memperbarui

Satu lagi alasan mengapa membaca dokumentasi untuk Symfony tidak akan pernah ketinggalan zaman . Ada solusi sederhana untuk kasus spesifik saya dan mengatur field typeopsi empty_datake nilai default.

Sekali lagi, solusi ini hanya untuk skenario di mana input kosong dalam formulir menetapkan bidang DB ke nol.

Latar Belakang

Tidak ada jawaban sebelumnya yang membantu saya dengan skenario spesifik saya tetapi saya menemukan solusinya.

Saya memiliki bidang formulir yang harus berperilaku sebagai berikut:

  1. Tidak wajib, bisa dibiarkan kosong. (Digunakan 'wajib' => salah)
  2. Jika dibiarkan kosong, seharusnya default ke nilai yang diberikan. Untuk pengalaman pengguna yang lebih baik, saya tidak menetapkan nilai default pada bidang input melainkan menggunakan atribut html 'placeholder' karena kurang menonjol.

Saya kemudian mencoba semua rekomendasi yang diberikan di sini. Biarkan saya daftar mereka:

  • Tetapkan nilai default ketika untuk properti entitas:
<?php
/**
 * @Entity
 */
class myEntity {
    /**
     * @var string
     *
     * @Column(name="myColumn", type="string", length="50")
     */
    private $myColumn = 'myDefaultValue';
    ...
}
  • Gunakan anotasi opsi:
@ORM\Column(name="foo", options={"default":"foo bar"})
  • Tetapkan nilai default pada konstruktor:
/**
 * @Entity
 */
class myEntity {
    ...
    public function __construct()
    {
        $this->myColumn = 'myDefaultValue';
    }
    ...
}
Tidak ada yang berfungsi dan semua karena cara Symfony menggunakan kelas Entity Anda.

PENTING

Bidang formulir Symfony mengesampingkan nilai default yang ditetapkan pada kelas Entity. Artinya, skema Anda untuk DB Anda dapat memiliki nilai default yang ditentukan tetapi jika Anda membiarkan bidang yang tidak diperlukan kosong saat mengirimkan formulir Anda, bagian form->handleRequest()dalam form->isValid()metode Anda akan menimpa nilai-nilai default di Entitykelas Anda dan mengaturnya ke nilai-nilai bidang input. Jika nilai kolom input kosong, maka Entityproperti akan disetel ke null.

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

Solusi Saya

Tetapkan nilai default pada controller Anda setelah form->handleRequest()di dalam form->isValid()metode Anda :

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

Bukan solusi yang indah tetapi berhasil. Saya mungkin bisa membuat validation grouptetapi mungkin ada orang yang melihat masalah ini sebagai transformasi data daripada validasi data , saya serahkan kepada Anda untuk memutuskan.


Override Setter (Tidak Bekerja)

Saya juga mencoba menimpa Entitysetter dengan cara ini:

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

    return $this;
}
...

Ini, meskipun terlihat lebih bersih, itu tidak berhasil . Alasannya adalah bahwa form->handleRequest()metode jahat tidak menggunakan metode setter Model untuk memperbarui data (gali form->setData()lebih detail).

Callistino
sumber
Jawaban ini pasti menuju ke atas. Komponen formulir menggunakan PropertyAccessor untuk mendapatkan dan mengatur nilai untuk properti Anda. Mungkin accessor properti harus menggunakan metode ketika mereka tersedia?
Xobb
1
kolom boolean tidak mendukung default dari php, jadi hanya anotasi
Crusader
Ini adalah satu-satunya solusi yang berfungsi ketika info berasal dari formulir. Saya juga tidak setuju dengan komentar di atas tentang boolean. Mereka tidak menerima anotasi default.
BernardA
Komponen formulir symfony menggunakan setter model tetapi hanya ketika model memformat data formulir berbeda dengan data yang dikembalikan oleh pengambil yang sesuai contoh objek model. Jika Anda memiliki metode penyetel / pengambil kustom - gunakan opsi formulir "property_path" (akan ditangani oleh PropertyAccessor) atau custom DataMapper (memungkinkan untuk menentukan rutin transfer data secara manual antara objek formulir dan model).
Arkemlar
1
Pertanyaan ini adalah tentang doktrin, bukan symfony, jadi jawaban ini tidak sesuai topik.
Omn
18

Solusi yang saya gunakan adalah a LifeCycleCallback. Masih menunggu untuk melihat apakah ada metode "asli" lagi, misalnya @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
sumber
1
Untuk pembaca masa depan, jangan mengandalkan daur ulang siklus hidup :) bahkan Marco Pivetta menentang mereka.
emix
Peringatan! Jika Entitas telah menetapkan properti dtPosted, maka kode Anda hanya akan menimpa properti. Selalu gunakan pengakses jika ada! if (!$this->getDtPosted()) { $this->setDtPosted(new \DateTime()); }
Barh
13

Anda dapat melakukannya menggunakan xml juga:

<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
sumber
8

Inilah cara saya menyelesaikannya untuk diri saya sendiri. Di bawah ini adalah contoh Entitas dengan nilai default untuk MySQL. Namun, ini juga memerlukan pengaturan konstruktor di entitas Anda, dan bagi Anda untuk menetapkan nilai default di sana.

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'
Putna
sumber
Dengan baris ini di config saya Doctrine mencoba untuk menjatuhkan default pada kolom setiap kali saya menjalankan. php app / console doctrine: schema: update
shapeshifter
1
Ini jawaban terburuk di sini. columnDefinitionberjalan langsung ke tujuan memiliki ORM, yang merupakan abstraksi dari database. Solusi ini akan merusak portabilitas, akan membuat perangkat lunak Anda bergantung pada vendor DB Anda dan juga akan merusak alat-alat Migrasi Doctrine.
Pedro Cordeiro
@PedroCordeiro Saya sepenuhnya setuju dengan Anda. Ini hanyalah solusi cepat sampai masalah lain muncul.
Putna
7

Bekerja untuk saya di database mysql juga:

Entity\Entity_name:
    type: entity
    table: table_name
    fields: 
        field_name:
            type: integer
            nullable: true
            options:
                default: 1
Alex Hoang
sumber
Dalam format anotasi untuk siapa yang tertarik: @ORM \ Column (name = "Entity_name", ketik = "integer", options = {"default" = "1"})
Hannes
7

Tak satu pun dari ini bekerja untuk saya. Saya menemukan beberapa dokumentasi di situs doktrin yang mengatakan untuk mengatur nilai secara langsung untuk menetapkan nilai default.

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;

Ini memasukkan nilai yang saya inginkan.

metric152
sumber
Silakan ubah tautan ke doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/… Lihat Butir 3.2.2. Bagaimana saya bisa menambahkan nilai default ke kolom?
Tobi
3

Menambahkan ke @romanb jawaban yang brilian.

Ini menambahkan sedikit overhead dalam migrasi, karena Anda jelas tidak dapat membuat bidang tanpa batasan nol dan tanpa nilai default.

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

Dengan jawaban ini, saya mendorong Anda untuk berpikir mengapa Anda memerlukan nilai default di database? Dan biasanya itu memungkinkan pembuatan objek tanpa kendala nol.

Dziamid
sumber
3

Jika Anda menggunakan definisi yaml untuk entitas Anda, berikut ini berfungsi untuk saya pada database postgresql:

Entity\Entity_name:
    type: entity
    table: table_name
    fields: 
        field_name:
            type: boolean
            nullable: false
            options:
                default: false
wonzbak
sumber
1
Bagaimana jika Anda tidak menggunakannya $entity->setFieldName()sebelum memerah? Doktrin tampaknya mendefinisikan nilai default pada nol. Satu-satunya solusi di yaml adalah mendefinisikan nilai default DI kelas entitas yang tampaknya bodoh bagi saya karena sudah didefinisikan dalam yaml ... -_-
j0k
1

Saya berjuang dengan masalah yang sama. Saya ingin memiliki nilai default dari database ke entitas (secara otomatis). Coba tebak, saya berhasil :)

<?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
sumber
3
Kembali ke ini sejak beberapa tahun saya sarankan Anda untuk tidak menggunakan pendekatan ini, itu benar-benar hack yang hack.
Steffen Brem
Karena Anda tidak merekomendasikan jawaban Anda sendiri, sebaiknya hapus saja;)
Dragos
1

Sementara menetapkan nilai dalam konstruktor akan berhasil, menggunakan peristiwa Siklus Hidup Ajaran mungkin merupakan solusi yang lebih baik.

Dengan memanfaatkan prePersistPeristiwa Siklus Hidup, Anda dapat menetapkan nilai default pada entitas Anda hanya pada bertahan awal.

tiruncula
sumber
Menggunakan acara siklus hidup dianggap a hack. Jangan pernah mengandalkan peretasan.
emix
0

Hati-hati saat menetapkan nilai default pada definisi properti! Sebaliknya, lakukan di konstruktor, agar bebas masalah. Jika Anda mendefinisikannya pada definisi properti, maka tetap objek ke database, kemudian buat sebagian beban, maka properti tidak dimuat lagi akan memiliki nilai default. Itu berbahaya jika Anda ingin tetap objek lagi.

Tomazahlin
sumber