Come posso impostare un valore predefinito in Doctrine 2?
Come posso impostare un valore predefinito in Doctrine 2?
Risposte:
I valori predefiniti del database non sono supportati "portabilmente". L'unico modo per utilizzare i valori predefiniti del database è tramite l' columnDefinition
attributo di mappatura in cui si specifica lo SQL
snippet ( DEFAULT
causa 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).
<?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 BLOB
e TEXT
.
options={"default": 0}
attenzione a usare "e non", poiché causa errori nella mia versione di dottrina.
Imposta un costruttore nella tua entità e imposta qui il valore predefinito.
Uso:
options={"default":"foo bar"}
e non:
options={"default"="foo bar"}
Per esempio:
/**
* @ORM\Column(name="foo", type="smallint", options={"default":0})
*/
private $foo
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 type
opzioneempty_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.
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:
Ho quindi provato tutte le raccomandazioni fornite qui. Vorrei elencarli:
<?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';
}
...
}
Niente di tutto ha funzionato e tutto a causa di come Symfony usa la tua classe Entity.
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 Entity
classe e li imposterai sui valori del campo di input. Se i valori del campo di input sono vuoti, imposterà la Entity
proprietà su null
.
http://symfony.com/doc/current/book/forms.html#handling-form-submissions
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 group
ma potrebbero esserci persone che vedono questo problema come una trasformazione dei dati piuttosto che una convalida dei dati , lascio a voi decidere.
Ho anche provato a scavalcare il Entity
setter 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).
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');
}
if (!$this->getDtPosted()) { $this->setDtPosted(new \DateTime()); }
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>
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'
columnDefinition
va 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.
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
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.
private $default = 0;
Questo ha inserito il valore che volevo.
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.
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
$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 ... -_-
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";
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' prePersist
evento Ciclo di vita, è possibile impostare il valore predefinito sull'entità solo su persist iniziale.
hack
. Non fare mai affidamento sugli hack.
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.