¿Cómo configuro un valor predeterminado en Doctrine 2?
¿Cómo configuro un valor predeterminado en Doctrine 2?
Respuestas:
Los valores predeterminados de la base de datos no son compatibles con "portabilidad". La única forma de usar los valores predeterminados de la base de datos es a través del columnDefinition
atributo de mapeo donde especifica el SQL
fragmento (DEFAULT
causa inclusiva) para la columna a la que se asigna el campo.
Puedes usar:
<?php
/**
* @Entity
*/
class myEntity {
/**
* @var string
*
* @Column(name="myColumn", type="string", length="50")
*/
private $myColumn = 'myDefaultValue';
...
}
Se prefieren los valores predeterminados de nivel PHP, ya que también están disponibles correctamente en los objetos recién creados y persistentes (Doctrine no volverá a la base de datos después de persistir en un nuevo objeto para obtener los valores predeterminados).
<?php
/**
* @Entity
*/
class myEntity {
/**
* @var string
*
* @ORM\Column(name="myColumn", type="integer", options={"default" : 0})
*/
private $myColumn;
...
}
Tenga en cuenta que esto usa SQL DEFAULT
, que no es compatible con algunos campos como BLOB
y TEXT
.
options={"default": 0}
tenga cuidado de usar "y no", ya que causa errores en mi versión de la doctrina.
Configure un constructor en su entidad y establezca el valor predeterminado allí.
Utilizar:
options={"default":"foo bar"}
y no:
options={"default"="foo bar"}
Por ejemplo:
/**
* @ORM\Column(name="foo", type="smallint", options={"default":0})
*/
private $foo
Una razón más por la que leer la documentación de Symfony nunca pasará de moda. Hay una solución simple para mi caso específico y es configurar la field type
opciónempty_data
en un valor predeterminado.
Nuevamente, esta solución es solo para el escenario donde una entrada vacía en un formulario establece el campo DB en nulo.
Ninguna de las respuestas anteriores me ayudó con mi escenario específico, pero encontré una solución.
Tenía un campo de formulario que debía comportarse de la siguiente manera:
Luego probé todas las recomendaciones dadas aquí. Déjame enumerarlos:
<?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 de eso funcionó y todo por cómo Symfony usa tu clase de entidad.
Los campos de formulario de Symfony anulan los valores predeterminados establecidos en la clase Entity.
Es decir, su esquema para su base de datos puede tener un valor predeterminado definido, pero si deja un campo no requerido vacío al enviar su formulario, el form->handleRequest()
interior de su form->isValid()
método anulará esos valores predeterminados en su Entity
clase y los establecerá en los valores del campo de entrada. Si los valores del campo de entrada están en blanco, establecerá la Entity
propiedad en null
.
http://symfony.com/doc/current/book/forms.html#handling-form-submissions
Establezca el valor predeterminado en su controlador después de form->handleRequest()
dentro de su form->isValid()
método:
...
if ($myEntity->getMyColumn() === null) {
$myEntity->setMyColumn('myDefaultValue');
}
...
No es una solución hermosa pero funciona. Probablemente podría hacer un validation group
pero puede haber personas que vean este problema como una transformación de datos en lugar de una validación de datos , lo dejo a usted para decidir.
También intenté anular el Entity
setter de esta manera:
...
/**
* Set myColumn
*
* @param string $myColumn
*
* @return myEntity
*/
public function setMyColumn($myColumn)
{
$this->myColumn = ($myColumn === null || $myColumn === '') ? 'myDefaultValue' : $myColumn;
return $this;
}
...
Esto, a pesar de que se ve más limpio, no funciona . La razón es que el form->handleRequest()
método malvado no usa los métodos de establecimiento del Modelo para actualizar los datos (profundice form->setData()
para obtener más detalles).
La solución que usé fue a LifeCycleCallback
. Todavía estoy esperando ver si hay algún otro método "nativo", por ejemplo @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()); }
También puedes hacerlo usando 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>
Así es como lo resolví por mí mismo. A continuación se muestra un ejemplo de entidad con valor predeterminado para MySQL. Sin embargo, esto también requiere la configuración de un constructor en su entidad, y para que establezca el valor predeterminado allí.
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
va directamente contra el propósito de tener un ORM, que es la abstracción de la base de datos. Esta solución romperá la portabilidad, mantendrá su software dependiente de su proveedor de DB y también romperá las herramientas de Doctrine Migrations.
Funciona para mí en una base de datos mysql también:
Entity\Entity_name:
type: entity
table: table_name
fields:
field_name:
type: integer
nullable: true
options:
default: 1
Nada de esto funcionó para mí. Encontré documentación en el sitio de doctrina que dice establecer el valor directamente para establecer un valor predeterminado.
private $default = 0;
Esto insertó el valor que quería.
Agregando a @romanb una respuesta brillante.
Esto agrega un poco de sobrecarga en la migración, porque obviamente no puede crear un campo sin restricción nula y sin valor predeterminado.
// 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");
Con esta respuesta, le animo a que piense, ¿por qué necesita el valor predeterminado en la base de datos en primer lugar? Y generalmente es para permitir crear objetos sin restricciones nulas.
Si usa la definición yaml para su entidad, lo siguiente funciona para mí en una base de datos postgresql:
Entity\Entity_name:
type: entity
table: table_name
fields:
field_name:
type: boolean
nullable: false
options:
default: false
$entity->setFieldName()
antes de enjuagar? Doctrine parece definir el valor predeterminado en nulo. La única solución en yaml es definir el valor predeterminado EN la clase de entidad que me parece tonto ya que ya está definido en el yaml ... -_-
Luché con el mismo problema. Quería tener el valor predeterminado de la base de datos en las entidades (automáticamente). Adivina qué, lo hice :)
<?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";
Si bien establecer el valor en el constructor funcionaría, usar los eventos de Doctrine Lifecycle podría ser una mejor solución.
Al aprovechar el prePersist
Evento del ciclo de vida, puede establecer su valor predeterminado en su entidad solo en la persistencia inicial.
hack
. Nunca confíes en hacks.
¡Tenga cuidado al establecer valores predeterminados en la definición de propiedad! Hazlo en el constructor, para mantenerlo libre de problemas. Si lo define en la definición de propiedad, luego persiste el objeto en la base de datos, luego realiza una carga parcial, luego las propiedades no cargadas nuevamente tendrán el valor predeterminado. Eso es peligroso si desea persistir el objeto nuevamente.