Valore predefinito in Doctrine


338

Come posso impostare un valore predefinito in Doctrine 2?


26
@ORM \ Column (name = "foo", type = "decimal", precision = 7, scale = 2, options = {"default" = 0}) funziona (dalla risposta non popolare di seguito)
WayFarer

2
@ORM \ Column (name = "is_activated", type = "boolean", options = {"default": 0}) OPPURE @ORM \ Column (name = "is_activated", type = "boolean", options = {"default "= 0})
ahmed hamdy,

Ahmed, questo non sembra funzionare per i booleani in Symfony 2.3. Tuttavia options = {"default" = "0"}) funziona, mettendo il numero intero tra virgolette.
Acyra

4
Se è un valore booleano, perché non stai usando: options = {"default": false}?
robocoder,

Risposte:


385

I valori predefiniti del database non sono supportati "portabilmente". L'unico modo per utilizzare i valori predefiniti del database è tramite l' columnDefinitionattributo di mappatura in cui si specifica lo SQLsnippet ( DEFAULTcausa inclusiva) per la colonna su cui è mappato il campo.

Puoi usare:

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

I valori predefiniti a livello di PHP sono preferiti poiché sono anche disponibili su oggetti appena creati e persistenti (Doctrine non tornerà al database dopo aver persistito un nuovo oggetto per ottenere i valori predefiniti).


11
ma qui c'è un problema: cosa succede se imposto un tipo "datetime"?
artragis,

46
@artragis mise il tuo istanciation nel costruttore dell'entità
Alain Tiemblo,

16
Bisogna fare attenzione alle migrazioni usando questo approccio poiché qualsiasi riga esistente causerà il fallimento della migrazione.
Tamlyn,

7
Non utilizzare l'area di istanza per impostare le variabili ... Fidati di me, accadrà qualcosa di brutto. Utilizzare invece l'area del costruttore.
mimoralea,

4
Raccomando di usare la columnDefinition nell'annotazione, o qualcuno userà il client mysql o phpmyadmin e i valori saranno sbagliati ...
NDM,

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

Si noti che questo utilizza SQL DEFAULT, che non è supportato per alcuni campi come BLOBe TEXT.


4
Buona pesca! Sembra che non ci siano opzioni = {"default" = 0} opzione nella documentazione ufficiale
WayFarer

2
Cordiali saluti, il optionsparametro è utile anche per i unsignedvalori. vedi questa risposta
yvoyer

5
Uso sia questa che la risposta accettata per coprire tutte le basi. Anche solo una nota che puoi anche fare: fai options={"default": 0}attenzione a usare "e non", poiché causa errori nella mia versione di dottrina.
Scott Flack,

28
Questa dovrebbe essere la risposta selezionata!
Acelasi Eu,

2
@Matt ha probabilmente detto che, poiché si trattava di una funzionalità non documentata, e le funzionalità non documentate sono inclini a essere rimosse. Come è documentato ora, dovresti essere sicuro di usarlo.
JCM

62

Imposta un costruttore nella tua entità e imposta qui il valore predefinito.


Questo sembra certamente l'approccio logico. Qualcuno ha riscontrato problemi con l'impostazione delle impostazioni predefinite nel costruttore?
cantera,

26
La soluzione raccomandata da Doctrine: doctrine-project.org/docs/orm/2.1/en/reference/faq.html
cantera,

@ cantera25 che dovrebbe essere la risposta +1
Phill Pafford,

3
questo non aggiorna le entità esistenti se aggiungi un nuovo campo che deve avere un valore predefinito. quindi no, quella non dovrebbe essere la risposta. dipende da cosa esattamente devi fare
Tomáš Tibenský,

Non funzionerà neanche a scopo di aggiornamento. Se vuoi tornare al valore predefinito semplicemente svuotando il campo (anche per intero), sfortunatamente, non funzionerà.
ThEBiShOp


51

Aggiornare

Un motivo in più per cui leggere la documentazione di Symfony non passerà mai di moda. C'è una soluzione semplice per il mio caso specifico ed è quella di impostare l' field typeopzioneempty_data su un valore predefinito.

Ancora una volta, questa soluzione è solo per lo scenario in cui un input vuoto in un modulo imposta il campo DB su null.

sfondo

Nessuna delle risposte precedenti mi ha aiutato con il mio scenario specifico, ma ho trovato una soluzione.

Avevo un campo modulo che doveva comportarsi come segue:

  1. Non richiesto, potrebbe essere lasciato in bianco. (Usato 'richiesto' => falso)
  2. Se lasciato vuoto, dovrebbe essere impostato su un determinato valore. Per una migliore esperienza utente, non ho impostato il valore predefinito nel campo di input ma ho piuttosto usato l'attributo html 'segnaposto' poiché è meno invadente.

Ho quindi provato tutte le raccomandazioni fornite qui. Vorrei elencarli:

  • Imposta un valore predefinito quando per la proprietà entità:
<?php
/**
 * @Entity
 */
class myEntity {
    /**
     * @var string
     *
     * @Column(name="myColumn", type="string", length="50")
     */
    private $myColumn = 'myDefaultValue';
    ...
}
  • Usa l'annotazione delle opzioni:
@ORM\Column(name="foo", options={"default":"foo bar"})
  • Imposta il valore predefinito sul costruttore:
/**
 * @Entity
 */
class myEntity {
    ...
    public function __construct()
    {
        $this->myColumn = 'myDefaultValue';
    }
    ...
}
Niente di tutto ha funzionato e tutto a causa di come Symfony usa la tua classe Entity.

IMPORTANTE

I campi modulo di symfony hanno la precedenza sui valori predefiniti impostati nella classe Entity. In altre parole, lo schema per il tuo DB può avere un valore predefinito definito ma se lasci vuoto un campo non richiesto durante l'invio del modulo, form->handleRequest()all'interno del tuo form->isValid()metodo verranno sovrascritti quei valori predefiniti sulla tua Entityclasse e li imposterai sui valori del campo di input. Se i valori del campo di input sono vuoti, imposterà la Entityproprietà su null.

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

La mia soluzione alternativa

Impostare il valore predefinito sul controller dopo form->handleRequest()all'interno del form->isValid()metodo:

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

Non è una bella soluzione ma funziona. Probabilmente potrei fare un, validation groupma potrebbero esserci persone che vedono questo problema come una trasformazione dei dati piuttosto che una convalida dei dati , lascio a voi decidere.


Sostituisci setter (non funziona)

Ho anche provato a scavalcare il Entitysetter in questo modo:

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

    return $this;
}
...

Questo, anche se sembra più pulito, non funziona . Il motivo è che il form->handleRequest()metodo malvagio non utilizza i metodi setter del Modello per aggiornare i dati (approfondire form->setData()per maggiori dettagli).


Questa risposta dovrebbe sicuramente arrivare all'inizio. Il componente Modulo utilizza PropertyAccessor per ottenere e impostare i valori per le proprietà. Forse il programma di accesso alla proprietà dovrebbe usare i metodi quando sono disponibili?
Xobb,

1
le colonne booleane non supportano i valori predefiniti di php, quindi solo le annotazioni
Crusader

Questa è l'unica soluzione che ha funzionato quando le informazioni provengono dai moduli. Inoltre non sono d'accordo con i commenti sopra riguardanti il ​​booleano. Non accettano l'annotazione predefinita.
Bernard:

Il componente del form di symfony usa i setter del modello ma solo quando i dati del formato del modello del modulo differiscono con i dati restituiti dal corrispondente getter dell'istanza dell'oggetto modello. Se hai i tuoi metodi setter / getter personalizzati - usa l'opzione del modulo "percorso_proprietà" (sarà gestito da PropertyAccessor) o DataMapper personalizzato (consente di definire manualmente la routine di trasferimento dati tra modulo e oggetto modello).
Arkemlar,

1
Questa domanda riguarda la dottrina, non symfony, quindi questa risposta non è proprio sull'argomento.
Omn,

18

La soluzione alternativa che ho usato era a LifeCycleCallback. Aspetto ancora di vedere se esiste un altro metodo "nativo", per esempio @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
Per i futuri lettori, non fare affidamento sui callback del ciclo di vita :) anche Marco Pivetta è contro di loro.
emix

Avvertimento! Se l'Entità ha già impostato la proprietà dtPosted, il codice sovrascriverà semplicemente la proprietà. Usa sempre gli accessori se esistono! if (!$this->getDtPosted()) { $this->setDtPosted(new \DateTime()); }
Barh,

13

Puoi farlo anche usando 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

Ecco come l'ho risolto da solo. Di seguito è riportato un esempio di entità con valore predefinito per MySQL. Tuttavia, ciò richiede anche la configurazione di un costruttore nella tua entità e la possibilità di impostare lì il valore predefinito.

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'

Con questa riga nella mia configurazione, Doctrine tenta di eliminare l'impostazione predefinita sulla colonna ogni volta che corro. dottrina php app / console: schema: update
shapeshifter

1
Questa è la risposta peggiore qui. columnDefinitionva direttamente allo scopo di avere un ORM, che è l'astrazione dal database. Questa soluzione interromperà la portabilità, manterrà il vostro software dipendente dal vostro fornitore di database e romperà anche gli strumenti di migrazione di Doctrine.
Pedro Cordeiro,

@PedroCordeiro Sono completamente d'accordo con te. Questa è solo una soluzione rapida fino a quando non sorge un altro problema.
Putna,

7

Funziona per me su un database mysql anche:

Entity\Entity_name:
    type: entity
    table: table_name
    fields: 
        field_name:
            type: integer
            nullable: true
            options:
                default: 1

Nel formato di annotazione per chi è interessato: @ORM \ Column (name = "Entity_name", type = "integer", options = {"default" = "1"})
Hannes

7

Niente di tutto questo ha funzionato per me. Ho trovato della documentazione sul sito di Dottrine che dice di impostare direttamente il valore per impostare un valore predefinito.

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;

Questo ha inserito il valore che volevo.


Modifica il link in doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/… Vedi punto 3.2.2. Come posso aggiungere valori predefiniti a una colonna?
Tobi,


3

Aggiungendo alla brillante risposta di @romanb.

Ciò aggiunge un leggero sovraccarico nella migrazione, perché ovviamente non è possibile creare un campo senza vincolo nullo e senza valore predefinito.

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

Con questa risposta, ti incoraggio a pensare in primo luogo perché hai bisogno del valore predefinito nel database? E di solito è per consentire la creazione di oggetti con vincolo non nullo.


3

Se usi la definizione di yaml per la tua entità, per me funziona su un database postgresql:

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

1
Cosa succede se non si utilizza $entity->setFieldName()prima del lavaggio? La dottrina sembra definire il valore predefinito su null. L'unica soluzione in yaml è definire il valore predefinito IN nella classe di entità che mi sembra stupido poiché è già definito in yaml ... -_-
j0k

1

Ho lottato con lo stesso problema. Volevo avere il valore predefinito dal database nelle entità (automaticamente). Indovina, l'ho fatto :)

<?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
Tornando a questo da più di qualche anno, ti consiglio di non usare questo approccio, è davvero un hack confuso.
Steffen Brem,

Dal momento che non consigli la tua risposta, potresti anche eliminarla;)
Dragos

1

Mentre l'impostazione del valore nel costruttore funzionerebbe, l'uso degli eventi del ciclo di vita di Doctrine potrebbe essere una soluzione migliore.

Sfruttando l' prePersistevento Ciclo di vita, è possibile impostare il valore predefinito sull'entità solo su persist iniziale.


L'uso degli eventi del ciclo di vita è considerato a hack. Non fare mai affidamento sugli hack.
emix

0

Fare attenzione quando si impostano i valori predefiniti sulla definizione della proprietà! Fallo invece nel costruttore, per mantenerlo senza problemi. Se lo si definisce sulla definizione della proprietà, quindi si persiste l'oggetto nel database, quindi si esegue un caricamento parziale, quindi le proprietà non caricate avranno nuovamente il valore predefinito. Ciò è pericoloso se si desidera persistere nuovamente l'oggetto.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.