Як встановити значення за замовчуванням у Doctrine 2?
Як встановити значення за замовчуванням у Doctrine 2?
Відповіді:
Значення за замовчуванням бази даних не підтримуються "портативно". Єдиний спосіб використання значень за замовчуванням бази даних - це columnDefinition
атрибут mapping, де ви вказуєте SQL
фрагмент ( DEFAULT
причину включно) для стовпчика, у який відображено поле.
Ви можете використовувати:
<?php
/**
* @Entity
*/
class myEntity {
/**
* @var string
*
* @Column(name="myColumn", type="string", length="50")
*/
private $myColumn = 'myDefaultValue';
...
}
Значення за замовчуванням на рівні PHP є кращими, оскільки вони також належним чином доступні для новостворених та збережених об'єктів (Доктрина не повернеться до бази даних після збереження нового об’єкта для отримання значень за замовчуванням).
<?php
/**
* @Entity
*/
class myEntity {
/**
* @var string
*
* @ORM\Column(name="myColumn", type="integer", options={"default" : 0})
*/
private $myColumn;
...
}
Зауважте, що для цього використовується SQL DEFAULT
, який не підтримується для деяких полів, таких як BLOB
і TEXT
.
options={"default": 0}
будьте обережні, щоб використовувати "і ні", оскільки це спричиняє помилки в моїй версії доктрини.
Налаштуйте конструктор у вашій сутності та встановіть там значення за замовчуванням.
Використання:
options={"default":"foo bar"}
і ні:
options={"default"="foo bar"}
Наприклад:
/**
* @ORM\Column(name="foo", type="smallint", options={"default":0})
*/
private $foo
Ще одна причина, чому читати документацію для Symfony ніколи не вийде з тренду. Існує просте рішення для мого конкретного випадку і полягає у встановленні для field type
параметра empty_data
значення за замовчуванням.
Знову ж таки, це рішення є лише для сценарію, коли порожнє введення у формі встановлює нульове поле БД.
Жодна з попередніх відповідей не допомогла мені в конкретному сценарії, але я знайшов рішення.
У мене було поле форми, яке потрібно було поводити так:
Потім я спробував усі рекомендації, наведені тут. Дозвольте мені перерахувати їх:
<?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';
}
...
}
Нічого не працювало, і все через те, як Symfony використовує ваш клас Entity.
Поля форми Symfony переосмислюють значення за замовчуванням, встановлені для класу Entity.
Тобто, у вашій схемі для вашої БД може бути визначено значення за замовчуванням, але якщо ви не залишите необов’язкове поле під час подання форми, form->handleRequest()
всередині вашого form->isValid()
методу буде замінено ці значення за замовчуванням у вашому Entity
класі та встановлено їх на значення поля введення. Якщо значення поля введення порожні, то воно встановить Entity
властивість null
.
http://symfony.com/doc/current/book/forms.html#handling-form-submissions
Встановіть значення за замовчуванням на контролері після form->handleRequest()
вашого form->isValid()
методу:
...
if ($myEntity->getMyColumn() === null) {
$myEntity->setMyColumn('myDefaultValue');
}
...
Не красиве рішення, але воно працює. Я, мабуть, міг би зробити, validation group
але можуть бути люди, які сприймають цю проблему як перетворення даних, а не перевірку даних , я залишаю це вам вирішити.
Я також спробував перемогти Entity
сетер таким чином:
...
/**
* Set myColumn
*
* @param string $myColumn
*
* @return myEntity
*/
public function setMyColumn($myColumn)
{
$this->myColumn = ($myColumn === null || $myColumn === '') ? 'myDefaultValue' : $myColumn;
return $this;
}
...
Це, хоч і виглядає чистіше, але не працює . Причина полягає в тому, що злий form->handleRequest()
метод не використовує методи встановлення Моделі для оновлення даних ( form->setData()
перегляньте детальніше).
Я вирішив цей спосіб 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');
}
if (!$this->getDtPosted()) { $this->setDtPosted(new \DateTime()); }
Ви також можете це зробити, використовуючи 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>
Ось як я це вирішив для себе. Нижче наведено приклад Entity із значенням за замовчуванням для 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'
columnDefinition
йде безпосередньо до мети створення ORM, яка є абстрагуванням від бази даних. Це рішення порушить портативність, забезпечить залежність вашого програмного забезпечення від постачальника даних DB, а також порушить інструменти міграції доктрин.
Для мене працює і база даних mysql:
Entity\Entity_name:
type: entity
table: table_name
fields:
field_name:
type: integer
nullable: true
options:
default: 1
Нічого цього не працювало для мене. Я знайшов деяку документацію на сайті доктрини, яка говорить про встановлення значення безпосередньо для встановлення значення за замовчуванням.
private $default = 0;
Це вставило потрібне мені значення.
Додавши до @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");
Відповідаючи на цю відповідь, я закликаю вас подумати, навіщо в першу чергу вам потрібне значення за замовчуванням у базі даних? І, як правило, це дозволяє створювати об'єкти з ненульовим обмеженням.
Якщо ви використовуєте визначення yaml для своєї організації, для мене в базі даних postgresql працює наступне:
Entity\Entity_name:
type: entity
table: table_name
fields:
field_name:
type: boolean
nullable: false
options:
default: false
$entity->setFieldName()
перед промиванням? Здається, доктрина визначає значення за замовчуванням у null. Єдине рішення в yaml - це визначити значення за замовчуванням IN -класу сутності, яке здається мені німим, оскільки воно вже визначене в yaml ... -_-
Я боровся з тією ж проблемою. Я хотів мати значення за замовчуванням з бази даних в сутності (автоматично). Здогадайтесь, що я це зробив :)
<?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";
Хоча встановлення значення в конструкторі спрацює, кращим рішенням може бути використання подій життєвого циклу доктрини.
Використовуючи prePersist
подію життєвого циклу, ви можете встановити значення за замовчуванням для вашої сутності лише на первісному збереженні.
hack
. Ніколи не покладайтеся на хаків.
Будьте уважні, встановлюючи значення за замовчуванням для визначення властивості! Зробіть це замість цього в конструкторі, щоб зберегти його без проблем. Якщо ви визначите його за визначенням властивості, то збережіть об'єкт у базі даних, потім зробіть часткове завантаження, тоді не завантажені властивості знову матимуть значення за замовчуванням. Це небезпечно, якщо ви хочете знову зберегти об'єкт.