Doctrine中的默认值

如何在原则2中设置默认值?

386370 次浏览

我使用的变通方法是LifeCycleCallback。还在等着看是否有更多的“本机”方法,例如@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');
}

数据库默认值不支持“可移植”。使用数据库默认值的唯一方法是通过columnDefinition映射属性,其中为字段映射到的列指定SQL片段(包括DEFAULT原因)。

你可以使用:

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

php级别的默认值是首选的,因为这些值在新创建的和持久化的对象上也是正确可用的(在持久化一个新对象后,Doctrine不会返回数据库以获得默认值)。

在实体中设置一个构造函数,并在那里设置默认值。

下面是我自己解决问题的方法。下面是MySQL默认值的实体示例。但是,这也需要在您的实体中设置一个构造函数,并在那里设置默认值。

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'
<?php
/**
* @Entity
*/
class myEntity {
/**
* @var string
*
* @ORM\Column(name="myColumn", type="integer", options={"default" : 0})
*/
private $myColumn;
...
}

注意,这里使用的是SQL DEFAULT,而某些字段如BLOBTEXT是不支持的。

为@romanb的精彩回答锦上添花。

这在迁移中增加了一点开销,因为您显然不能创建一个非空约束且没有默认值的字段。

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

有了这个答案,我鼓励您思考一下,为什么首先需要数据库中的默认值?通常它允许创建非空约束的对象。

使用:

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

而不是:

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

例如:

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

我也遇到过同样的问题。我希望将数据库中的默认值(自动地)放入实体中。你猜怎么着,我做到了。

<?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";

如果你的实体使用yaml定义, 以下工作为我postgresql数据库:

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

工作对我的mysql数据库也:

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

更新

Symfony的阅读文档永远不会过时的另一个原因。对于我的具体情况,有一个简单的解决方案,就是将field type选项empty_data设置为默认值。

同样,此解决方案仅适用于表单中的空输入将DB字段设置为null的场景。

背景

前面的答案对我的具体情况没有任何帮助,但我找到了一个解决方案。

我有一个表单字段,需要表现如下:

  1. 不是必需的,可以留空。(使用'required' => false)
  2. 如果为空,则默认为给定值。为了更好的用户体验,我没有在输入字段上设置默认值,而是使用html属性“占位符”,因为它不那么突兀。

然后我尝试了这里给出的所有建议。让我列出它们:

  • 为entity属性设置默认值:
<?php
/**
* @Entity
*/
class myEntity {
/**
* @var string
*
* @Column(name="myColumn", type="string", length="50")
*/
private $myColumn = 'myDefaultValue';
...
}
  • 使用options注释:
@ORM\Column(name="foo", options={"default":"foo bar"})
  • 在构造函数上设置默认值:
/**
* @Entity
*/
class myEntity {
...
public function __construct()
{
$this->myColumn = 'myDefaultValue';
}
...
}
所有这些都不能工作,这都是因为Symfony使用Entity类的方式。

重要的

Symfony form字段覆盖在Entity类上设置的默认值。 这意味着,你的数据库模式可以定义一个默认值,但如果你在提交表单时留下一个非必需字段为空,你的form->isValid()方法中的form->handleRequest()将覆盖你的Entity类中的这些默认值,并将它们设置为输入字段值。如果输入字段值为空,则将Entity属性设置为null.

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

我的解决方案

在你的form->isValid()方法中,在你的控制器form->handleRequest()之后设置默认值:

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

这不是一个漂亮的解决方案,但很有效。我可能会做一个validation group,但可能有人认为这个问题是数据转换而不是数据验证,我把它留给你决定。


覆盖设置器(不工作)

我还尝试以这种方式重写Entity setter:

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


return $this;
}
...

这个,尽管它看起来更干净,不管用。原因是邪恶的form->handleRequest()方法没有使用模型的setter方法来更新数据(更多细节请深入form->setData())。

这些对我都没用。我在doctrine的网站上找到了一些文档,上面说直接设置值来设置默认值。

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;

这将插入我想要的值。

你也可以使用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>

虽然在构造函数中设置值可以工作,但使用Doctrine Lifecycle事件可能是更好的解决方案。

通过利用prePersist生命周期事件,你可以只在初始化时为你的实体设置默认值。

在属性定义上设置默认值时要小心!在构造函数中执行,以避免出现问题。如果您在属性定义上定义它,然后将对象持久化到数据库,然后进行部分加载,那么未加载的属性将再次具有默认值。如果您想再次持久化对象,这是危险的。

下面是如何在PHP 8中使用属性来做到这一点。

#[ORM\Column(type: 'boolean', nullable: false, options: ['default' => 0])]
#[Assert\NotNull()]
private bool $isFavorite = false;