Wie stelle ich einen Standardwert in Doctrine 2 ein?
Datenbank-Standardwerte werden nicht "portabel" unterstützt. Datenbank-Standardwerte können nur über das Mapping-Attribut columnDefinition
verwendet werden, in dem Sie das SQL
-Snippet (einschließlich DEFAULT
cause) für die Spalte angeben, der das Feld zugeordnet ist.
Sie können verwenden:
<?php
/**
* @Entity
*/
class myEntity {
/**
* @var string
*
* @Column(name="myColumn", type="string", length="50")
*/
private $myColumn = 'myDefaultValue';
...
}
Standardwerte auf PHP-Ebene werden bevorzugt, da diese auch für neu erstellte und persistierte Objekte ordnungsgemäß verfügbar sind (Doctrine kehrt nicht zur Datenbank zurück, wenn ein neues Objekt persistent ist, um die Standardwerte zu erhalten).
<?php
/**
* @Entity
*/
class myEntity {
/**
* @var string
*
* @ORM\Column(name="myColumn", type="integer", options={"default" : 0})
*/
private $myColumn;
...
}
Beachten Sie, dass hier SQL DEFAULT
verwendet wird, die für einige Felder wie BLOB
und TEXT
nicht unterstützt wird.
Richten Sie einen Konstruktor in Ihrer Entität ein und legen Sie dort den Standardwert fest.
Benutzen:
options={"default":"foo bar"}
und nicht:
options={"default"="foo bar"}
Zum Beispiel:
/**
* @ORM\Column(name="foo", type="smallint", options={"default":0})
*/
private $foo
Ein weiterer Grund, warum Dokumentation lesenfür Symfony niemals aus dem Trend gerät. Für meinen speziellen Fall gibt es eine einfache Lösung. Sie setzen die field type
-Option empty_data
auf einen Standardwert.
Diese Lösung ist wiederum nur für das Szenario gedacht, bei dem eine leere Eingabe in einem Formular das DB-Feld auf Null setzt.
Keine der vorherigen Antworten hat mir in meinem spezifischen Szenario geholfen, aber ich habe eine Lösung gefunden.
Ich hatte ein Formularfeld, das sich wie folgt verhalten musste:
Ich habe dann alle Empfehlungen ausprobiert. Lass mich sie auflisten:
<?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-Formularfelder überschreiben die für die Entity-Klasse festgelegten Standardwerte. Das heißt, für Ihr Schema für Ihre Datenbank kann ein Standardwert definiert sein. Wenn Sie jedoch beim Senden eines Formulars ein nicht erforderliches Feld leer lassen, wird das form->handleRequest()
in Ihrer form->isValid()
-Methode überschreibt diese Standardwerte in Ihrer Entity
-Klasse und setzt sie auf die Eingabefeldwerte. Wenn die Eingabefeldwerte leer sind, wird die Entity
-Eigenschaft auf null
gesetzt.
http://symfony.com/doc/current/book/forms.html#handling-form-submissions
Legen Sie den Standardwert in Ihrem Controller nach form->handleRequest()
in Ihrer form->isValid()
-Methode fest:
...
if ($myEntity->getMyColumn() === null) {
$myEntity->setMyColumn('myDefaultValue');
}
...
Keine schöne Lösung, aber es funktioniert. Ich könnte wahrscheinlich einen validation group
machen, aber es gibt Leute, die dieses Problem als Datentransformation und nicht als Datenvalidierung betrachten. Ich überlasse es Ihnen, zu entscheiden.
Ich habe auch versucht, den Entity
-Setter folgendermaßen zu überschreiben:
...
/**
* Set myColumn
*
* @param string $myColumn
*
* @return myEntity
*/
public function setMyColumn($myColumn)
{
$this->myColumn = ($myColumn === null || $myColumn === '') ? 'myDefaultValue' : $myColumn;
return $this;
}
...
Auch wenn es sauberer aussieht, funktioniert nicht. Der Grund ist, dass die böse form->handleRequest()
-Methode die Setter-Methoden des Modells nicht zum Aktualisieren der Daten verwendet (Dig in form->setData()
für weitere Details).
Die verwendete Problemumgehung war eine LifeCycleCallback
. Wartet immer noch darauf, ob es noch eine "native" Methode gibt, zum Beispiel @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');
}
Sie können es auch mit XML tun:
<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>
So habe ich es für mich gelöst. Nachfolgend finden Sie ein Entity-Beispiel mit einem Standardwert für MySQL. Dies erfordert jedoch auch die Einrichtung eines Konstruktors in Ihrer Entität und die Festlegung des Standardwerts.
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'
Funktioniert für mich auch in einer MySQL-Datenbank:
Entity\Entity_name:
type: entity
table: table_name
fields:
field_name:
type: integer
nullable: true
options:
default: 1
Nichts davon funktionierte für mich. Ich habe auf der Website von Doctrine eine Dokumentation gefunden, die besagt, dass der Wert direkt gesetzt werden soll, um einen Standardwert festzulegen.
http://doctrine-orm.readthedocs.io/projects/doctrine-orm/de/latest/reference/faq.html
private $default = 0;
Dies fügte den gewünschten Wert ein.
Wenn Sie die yaml-Definition für Ihre Entität verwenden, funktioniert folgendes für eine Postgresql-Datenbank:
Entity\Entity_name:
type: entity
table: table_name
fields:
field_name:
type: boolean
nullable: false
options:
default: false
Hinzufügen zu @romanb brillante Antwort.
Dies führt zu einem gewissen Overhead bei der Migration, da Sie offensichtlich kein Feld ohne Einschränkung und ohne Standardwert erstellen können.
// 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");
Mit dieser Antwort ermutige ich Sie zu überlegen, warum Sie den Standardwert in der Datenbank überhaupt benötigen. Normalerweise ist es erlaubt, Objekte mit einer NULL-Einschränkung zu erstellen.
Wenn Sie den Wert im Konstruktor festlegen möchten, ist die Verwendung der Doctrine Lifecycle-Ereignisse möglicherweise eine bessere Lösung.
Durch die Nutzung des prePersist
Lifecycle-Ereignisses können Sie Ihren Standardwert für Ihre Entität nur bei der ersten Persistenz festlegen.
Ich hatte mit dem gleichen Problem zu kämpfen. Ich wollte den Standardwert aus der Datenbank in die Entitäten haben (automatisch). Weißt du was, ich habe es getan :)
<?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";
Seien Sie vorsichtig beim Festlegen von Standardwerten für die Eigenschaftsdefinition! Tun Sie es stattdessen im Konstruktor, um es problemlos zu halten. Wenn Sie es für die Eigenschaftsdefinition definieren, dann das Objekt in der Datenbank beibehalten, einen Teilladevorgang durchführen, dann haben die nicht geladenen Eigenschaften wieder den Standardwert. Das ist gefährlich, wenn Sie das Objekt erneut beibehalten möchten.