Valor padrão no Doctrine


338

Como defino um valor padrão no Doctrine 2?


26
@ORM \ Column (nome = "foo", tipo = "decimal", precisão = 7, escala = 2, opções = {"padrão" = 0}) funciona (da resposta não popular abaixo)
WayFarer

2
@ORM \ Column (nome = "is_activated", tipo = "boolean", opções = {"padrão": 0}) OU @ORM \ Column (nome = "is_activated", tipo = "boolean", opções = {"default "= 0})
ahmed hamdy

Ahmed, isso não parece funcionar para os booleanos no Symfony 2.3. No entanto, opções = {"padrão" = "0"}) funcionam, colocando o número inteiro entre aspas.
Acyra

4
Se é um booleano, por que você não está usando: options = {"default": false}?
Robocoder 12/10

Respostas:


385

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 columnDefinitionatributo de mapeamento no qual você especifica o SQLsnippet ( DEFAULTinclusive 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).


11
mas há um problema aqui: E se eu definir um tipo "datetime"?
Artragis

46
@artragis colocar sua instanciação no construtor entidade
Alain Tiemblo

16
É necessário tomar cuidado com as migrações usando essa abordagem, pois qualquer linha existente causará falha na migração.
Tamlyn

7
Não use a área de instanciação para definir variáveis ​​... Confie em mim, algo ruim acontecerá. Use a área do construtor.
mimoralea

4
Eu recomendo usar o ColumnDefinition na anotação, ou alguém vai usar o cliente mysql ou phpmyadmin e os valores serão errado ...
NDM

542
<?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 BLOBe TEXT.


4
Boa pegada! Parece não há opções = {= 0 "default"} opção na documentação oficial
Wayfarer

2
Para sua informação, o optionsparâmetro também é útil para unsignedvalores. veja esta resposta
yvoyer

5
Eu uso isso e a resposta aceita para cobrir todas as bases. Também apenas uma nota que você também pode fazer: options={"default": 0}Tenha o cuidado de utilização "e não', uma vez que provoca erros na minha versão da doutrina.
Scott Flack

28
Essa deve ser a resposta selecionada!
Acelasi Eu 23/09/14

2
@ Matt, ele provavelmente disse isso porque era um recurso não documentado, e os recursos não documentados podem ser removidos. Como está documentado agora, você deve usá-lo com segurança.
JCM

62

Configure um construtor em sua entidade e defina o valor padrão lá.


Isso certamente parece ser a abordagem lógica. Alguém já teve problemas com a configuração de padrões no construtor?
Cantera #

26

@ cantera25 que deve ser a resposta +1 #
Phill Pafford

3
isso não atualiza as entidades existentes se você adicionar um novo campo que precise ter valor padrão. então não, essa não deve ser a resposta. depende exatamente do que você precisa fazer
Tomáš Tibenský 4/16

Também não funcionará com a finalidade de atualização. Se você quiser voltar ao valor padrão apenas esvaziando o campo (mesmo para número inteiro), infelizmente isso não funcionará.
ThEBiShOp 20/09/16


51

Atualizar

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 typeopção empty_datapara 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.

fundo

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:

  1. Não é necessário, pode ser deixado em branco. (Usado 'obrigatório' => falso)
  2. Se deixado em branco, deve ser padronizado para um determinado valor. Para uma melhor experiência do usuário, não configurei o valor padrão no campo de entrada, mas usei o atributo html 'placeholder', pois é menos invasivo.

Eu então tentei todas as recomendações dadas aqui. Deixe-me listá-los:

  • Defina um valor padrão para a propriedade da entidade:
<?php
/**
 * @Entity
 */
class myEntity {
    /**
     * @var string
     *
     * @Column(name="myColumn", type="string", length="50")
     */
    private $myColumn = 'myDefaultValue';
    ...
}
  • Use a anotação de opções:
@ORM\Column(name="foo", options={"default":"foo bar"})
  • Defina o valor padrão no construtor:
/**
 * @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.

IMPORTANTE

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 Entityclasse e os definirá para os valores do campo de entrada. Se os valores do campo de entrada estiverem em branco, a Entitypropriedade será configurada para null.

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

Minha solução alternativa

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


Substituir setter (não funciona)

Eu também tentei substituir o Entitysetter 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).


Esta resposta deve ir ao topo, com certeza. O componente Form usa PropertyAccessor para obter e definir os valores para suas propriedades. Talvez o acessador de propriedade deva usar os métodos quando estiverem disponíveis?
Xobb

11
colunas boolean don `t padrões de apoio do php, portanto, apenas as anotações
Crusader

Esta é a única solução que funcionou quando as informações são provenientes de formulários. Também não concordo com os comentários acima sobre booleano. Eles não aceitam a anotação padrão.
Bernarda

O componente de formulário do Symfony usa configuradores de modelo, mas somente quando os dados de formato do modelo diferem dos dados retornados pelo getter correspondente da instância do objeto de modelo. Se você possui seus métodos setter / getter personalizados - use a opção de formulário "property_path" (será tratado pelo PropertyAccessor) ou o DataMapper personalizado (permite definir manualmente a rotina de transferência de dados entre o formulário e o objeto do modelo).
Arkemlar

11
Esta pergunta é sobre doutrina, não o symfony, portanto, esta resposta não está realmente no tópico.
Omn

18

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

11
Para futuros leitores, não confie nos retornos de chamada do ciclo de vida :) até Marco Pivetta é contra eles.
Em9 de

Atenção! Se a Entidade já tiver definido a propriedade dtPosted, seu código simplesmente substituirá a propriedade. Sempre use acessadores se eles existirem! if (!$this->getDtPosted()) { $this->setDtPosted(new \DateTime()); }
Barh

13

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>

8

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'

Com essa linha na minha configuração, o Doctrine tenta soltar o padrão na coluna toda vez que corro. php app / doutrina console: esquema: update
Metamorfo

11
Esta é a pior resposta aqui. columnDefinitionvai 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.
Pedro Cordeiro

@PedroCordeiro Concordo plenamente com você. Esta é apenas uma solução rápida até que outro problema ocorra.
Putna

7

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

Em formato de anotação para quem está interessado: @ORM \ Column (name = "entity_name", type = "integer", options = { "default" = "1"})
Hannes

7

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.

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;

Isso inseriu o valor que eu queria.


Por favor, mude o link para doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/… Ver ponto 3.2.2. Como posso adicionar valores padrão a uma coluna?
Tobi


3

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.


3

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

11
E se você não usasse $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 ... -_-
j0k

1

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

3
Voltando a isso depois de alguns anos, recomendo que você não use essa abordagem, é realmente um hack.
Steffen Brem

Como você não recomenda sua própria resposta, é possível excluí-la;) #
Dragos

1

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 prePersistEvento do Ciclo de Vida, você pode definir seu valor padrão em sua entidade apenas na persistência inicial.


O uso de eventos do ciclo de vida é considerado a hack. Nunca confie em hacks.
Emix 18/08

0

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.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.