webentwicklung-frage-antwort-db.com.de

Standardwert in Doctrine

Wie stelle ich einen Standardwert in Doctrine 2 ein?

296
Jiew Meng

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).

355
romanb
<?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.

457
iv3ndy

Richten Sie einen Konstruktor in Ihrer Entität ein und legen Sie dort den Standardwert fest.

61
Jeremy Hicks

Benutzen: 

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

und nicht: 

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

Zum Beispiel:

/**
* @ORM\Column(name="foo", type="smallint", options={"default":0})
*/
private $foo
53

Aktualisieren

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.

Hintergrund

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:

  1. Nicht erforderlich, kann leer bleiben. (Verwendete 'required' => false)
  2. Bleibt das Feld leer, sollte es einen vorgegebenen Wert annehmen. Für eine bessere Benutzererfahrung habe ich nicht den Standardwert für das Eingabefeld festgelegt, sondern das HTML-Attribut 'Platzhalter' verwendet, da es weniger aufdringlich ist.

Ich habe dann alle Empfehlungen ausprobiert. Lass mich sie auflisten:

  • Legen Sie einen Standardwert für die Entitätseigenschaft fest:
<?php
/**
 * @Entity
 */
class myEntity {
    /**
     * @var string
     *
     * @Column(name="myColumn", type="string", length="50")
     */
    private $myColumn = 'myDefaultValue';
    ...
}
  • Verwenden Sie die Optionsanmerkung:
@ORM\Column(name="foo", options={"default":"foo bar"})
  • Legen Sie den Standardwert für den Konstruktor fest:
/**
 * @Entity
 */
class myEntity {
    ...
    public function __construct()
    {
        $this->myColumn = 'myDefaultValue';
    }
    ...
}

WICHTIG

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

Mein Workaround

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.


Setzer überschreiben (funktioniert nicht)

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).

48
Callistino

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

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>
12
Andrew Zhilin

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'
7
Putna

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
7
Alex Hoang

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.

5
metric152

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
3
wonzbak

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.

2
Dziamid

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.

1
tiruncula

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";
1
Steffen Brem

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.

0
tomazahlin