Como defino um valor padrão no Doctrine 2?
Como defino um valor padrão no Doctrine 2?
Respostas:
Os valores padrão do banco de dados não são "portably" suportados. A única maneira de usar os valores padrão do banco de dados é através do columnDefinition
atributo de mapeamento no qual você especifica o SQL
snippet ( DEFAULT
inclusive causa) para a coluna na qual o campo é mapeado.
Você pode usar:
<?php
/**
* @Entity
*/
class myEntity {
/**
* @var string
*
* @Column(name="myColumn", type="string", length="50")
*/
private $myColumn = 'myDefaultValue';
...
}
Os valores padrão no nível PHP são preferidos, pois eles também estão disponíveis adequadamente em objetos recém-criados e persistentes (o Doctrine não retornará ao banco de dados após persistir em um novo objeto para obter os valores padrão).
<?php
/**
* @Entity
*/
class myEntity {
/**
* @var string
*
* @ORM\Column(name="myColumn", type="integer", options={"default" : 0})
*/
private $myColumn;
...
}
Observe que isso usa SQL DEFAULT
, que não é suportado em alguns campos como BLOB
e TEXT
.
options={"default": 0}
Tenha o cuidado de utilização "e não', uma vez que provoca erros na minha versão da doutrina.
Configure um construtor em sua entidade e defina o valor padrão lá.
Usar:
options={"default":"foo bar"}
e não:
options={"default"="foo bar"}
Por exemplo:
/**
* @ORM\Column(name="foo", type="smallint", options={"default":0})
*/
private $foo
Mais um motivo para ler a documentação do Symfony nunca sair de moda. Existe uma solução simples para o meu caso específico e é definir a field type
opção empty_data
para um valor padrão.
Novamente, esta solução é apenas para o cenário em que uma entrada vazia em um formulário define o campo DB como nulo.
Nenhuma das respostas anteriores me ajudou com meu cenário específico, mas eu encontrei uma solução.
Eu tinha um campo de formulário que precisava se comportar da seguinte maneira:
Eu então tentei todas as recomendações dadas aqui. Deixe-me listá-los:
<?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';
}
...
}
Nada disso funcionou e tudo por causa de como o Symfony usa sua classe de entidade.
Os campos do formulário do Symfony substituem os valores padrão definidos na classe Entity.
Ou seja, seu esquema para seu banco de dados pode ter um valor padrão definido, mas se você deixar um campo não obrigatório vazio ao enviar seu formulário, o método form->handleRequest()
interno form->isValid()
substituirá esses valores padrão em sua Entity
classe e os definirá para os valores do campo de entrada. Se os valores do campo de entrada estiverem em branco, a Entity
propriedade será configurada para null
.
http://symfony.com/doc/current/book/forms.html#handling-form-submissions
Defina o valor padrão no seu controlador depois de form->handleRequest()
dentro do seu form->isValid()
método:
...
if ($myEntity->getMyColumn() === null) {
$myEntity->setMyColumn('myDefaultValue');
}
...
Não é uma solução bonita, mas funciona. Provavelmente eu poderia fazer um, validation group
mas pode haver pessoas que veem esse problema como uma transformação de dados , e não como validação de dados , deixo para você decidir.
Eu também tentei substituir o Entity
setter desta maneira:
...
/**
* Set myColumn
*
* @param string $myColumn
*
* @return myEntity
*/
public function setMyColumn($myColumn)
{
$this->myColumn = ($myColumn === null || $myColumn === '') ? 'myDefaultValue' : $myColumn;
return $this;
}
...
Embora pareça mais limpo, não funciona . A razão é que o form->handleRequest()
método evil não usa os métodos setter do Model para atualizar os dados (procure form->setData()
mais detalhes).
A solução alternativa que usei foi a LifeCycleCallback
. Ainda estou esperando para ver se existe algum método "nativo", por exemplo @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()); }
Você pode fazer isso usando xml também:
<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>
Aqui está como eu resolvi isso sozinho. Abaixo está um exemplo de entidade com valor padrão para MySQL. No entanto, isso também requer a configuração de um construtor em sua entidade e para você definir o valor padrão lá.
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
vai diretamente contra o propósito de ter um ORM, que é uma abstração do banco de dados. Essa solução interromperá a portabilidade, manterá o software dependente do fornecedor do banco de dados e também interromperá as ferramentas de migração de doutrina.
Funciona para mim em um banco de dados mysql também:
Entity\Entity_name:
type: entity
table: table_name
fields:
field_name:
type: integer
nullable: true
options:
default: 1
Nada disso funcionou para mim. Encontrei alguma documentação no site da doutrina que diz para definir o valor diretamente para definir um valor padrão.
private $default = 0;
Isso inseriu o valor que eu queria.
Adicionando à resposta brilhante @romanb.
Isso adiciona um pouco de sobrecarga na migração, porque você obviamente não pode criar um campo sem restrição nula e sem valor padrão.
// 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");
Com esta resposta, encorajo você a pensar por que você precisa do valor padrão no banco de dados em primeiro lugar? E geralmente é para permitir a criação de objetos sem restrição nula.
Se você usar a definição de yaml para sua entidade, o seguinte funcionará para mim em um banco de dados postgresql:
Entity\Entity_name:
type: entity
table: table_name
fields:
field_name:
type: boolean
nullable: false
options:
default: false
$entity->setFieldName()
antes da descarga? A doutrina parece definir o valor padrão em nulo. A única solução em yaml é definir o valor padrão IN a classe de entidade que parece mudo para mim, uma vez que já está definido no yaml ... -_-
Eu lutei com o mesmo problema. Eu queria ter o valor padrão do banco de dados nas entidades (automaticamente). Adivinha o quê, eu fiz isso :)
<?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";
Embora a definição do valor no construtor funcione, o uso dos eventos do Ciclo de Vida do Doctrine pode ser uma solução melhor.
Ao alavancar o prePersist
Evento do Ciclo de Vida, você pode definir seu valor padrão em sua entidade apenas na persistência inicial.
hack
. Nunca confie em hacks.
Cuidado ao definir valores padrão na definição da propriedade! Faça-o no construtor, para mantê-lo livre de problemas. Se você defini-lo na definição da propriedade, persista o objeto no banco de dados, faça uma carga parcial e as propriedades não carregadas terão novamente o valor padrão. Isso é perigoso se você deseja persistir o objeto novamente.