I have an existing entity in database. I would like to add a new column to this entity:
/**
* #ORM\ManyToOne(targetEntity="Language")
* #ORM\JoinColumn(name="language_id", referencedColumnName="id", nullable=false)
*/
protected $language;
When I now use "vendor/bin/doctrine-migrate migrations:diff", the generated migration script does not contain a default value for language_id. Therefore the migration-script fails. Setting a default value for the property in the object does not help. How can I define a default value for the fk-column? I neither found something in doctrines documentation nor through google/stackoverflow.
If the column is not null then it should represent a valid relationship; assuming you use 0 instead, Doctrine will try to load the association using that, which would of course fail. In these cases you would need to update the database and mapping to allow a null value.
If however you require a default language association to be defined then you explicitly need to set it when you create the entity.
$language = $entityManager->find(1);
$entity = new Entity;
$entity->setLanguage($language);
$entityManager->persist($entity);
$entityManager->flush();
For this reason, you might want to consider a 'service' that encapsulates the creation of your entity so you know a language will always be valid and assigned by default.
It may not be a clean way to do it, but maybe you can execute the SQL query yourself and add manually the DEFAULT statement ?
ALTER TABLE registered_user ADD language_id VARCHAR(255) NOT NULL DEFAULT {default_value} WITH VALUES;
I'm quite surprised that adding a default property in the annotation is not working here!
Related
I cretead model, with columns:
like4u_id, vtope_id, panel_id
I set these columns option - Nullable, but if i save model, i get error:
SQLSTATE[HY000]: General error: 1366 Incorrect integer value: '' for
column 'like4u_id' at row 1 (SQL: update
master_vars set updated_at = 2018-05-23
16:03:14, like4u_id = , vtope_id = where id = 328)
What is the problem? It's field not required and column nullable..
It may happen with MySQL databases.
You need to use the Nullable trait in your model for set to NULL the attributes when left empty.
Here is the docs of the Nullable trait
When a form field is empty but should contain an "integer" value in the database some engines will try to insert an empty string into an integer field.
This is what causes the error message, basically trying to put the square through the round hole.
If you implement the Nullable trait you can make sure that these fields, if left empty are inserted as a true NULL instead of a string
I prefer to have my trait as a use statement above the class and then a short use int the class itself.
You can also put it directly in the class by use \October\Rain\Database\Traits\Nullable; instead of use Nullable; if you don't wish to have it appear in two spots. It's up to your preference.
use Model;
use October\Rain\Database\Traits\Nullable;
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/**
* Page Model
*/
class ModuleLink extends Model
{
public $table = 'your_table_name_here';
use Nullable; // This sets the trait to be used in this Model.
//^^^^^^^^^^^^^
public $nullable = [
'module_id', // Define which fields should be inserted as NULL when empty
'sort_order',
];
I have a relationship on one of my models:
/**
* #ORM\ManyToOne(targetEntity="Page", cascade="persist")
* #ORM\JoinColumn(name="page_id", referencedColumnName="id")
*/
private $parentPage;
And when I delete the parent page, I get this error:
Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails
Basically my models are a page, and page revision. When I delete the page I don't want to delete the revisions. I also want to keep the page_id on the page revisions (i.e. not set it to null).
How can I do this with Doctrine?
By definition you cannot delete the record that the foreign key is pointing at without setting the key to null (onDelete="SET NULL") or cascading the delete operation (There are two options - ORM Level: cascade={"remove"} | database level: onDelete="CASCADE"). There is the alternative of setting a default value of a still existing record, but you have to do that manually, I don't think Doctrine supports this "out-of-the-box" (please correct me if I am wrong, but in this case setting a default value is not desired anyway).
This strictness is reflecting the concept of having foreign key constraints; like #Théo said:
a FK is to ensure data consistency.
Soft delete (already mentioned) is one solution, but what you could also do is add an additional removed_page_id column that you sync with the page_id just before you delete it in a preRemove event handler (life cycle callback). Whether such information has any value I wonder but I guess you have some use for it, otherwise you wouldn't ask this question.
I am definitely not claiming this is good practice, but it is at least something that you can use for your edge case. So something in the line of:
In your Revision:
/**
* #ORM\ManyToOne(targetEntity="Page", cascade="persist")
* #ORM\JoinColumn(name="page_id", referencedColumnName="id", onDelete="SET NULL")
*/
private $parentPage;
/**
* #var int
* #ORM\Column(type="integer", name="removed_page_id", nullable=true)
*/
protected $removedPageId;
And then in your Page:
/**
* #ORM\PreRemove
*/
public function preRemovePageHandler(LifecycleEventArgs $args)
{
$entityManager = $args->getEntityManager();
$page = $args->getEntity();
$revisions = $page->getRevisions();
foreach($revisions as $revision){
$revision->setRemovedPageId($page->getId());
$entityManager->persist($revision);
}
$entityManager->flush();
}
Alternatively you could of course already set the correct $removedPageId value during construction of your Revision, then you don't even need to execute a life cycle callback on remove.
I solved this by overriding one doctrine class in symfony 4.3, it looks like this for me:
<?php declare(strict_types=1);
namespace App\DBAL;
use Doctrine\DBAL\Platforms\MySQLPlatform;
/**
* Class MySQLPlatformService
* #package App\DBAL
*/
class MySQLPlatformService extends MySQLPlatform
{
/**
* Disabling the creation of foreign keys in the database (partitioning is used)
* #return false
*/
public function supportsForeignKeyConstraints(): bool
{
return false;
}
/**
* Disabling the creation of foreign keys in the database (partitioning is used)
* #return false
*/
public function supportsForeignKeyOnUpdate(): bool
{
return false;
}
}
You can disable the exporting of foreign keys for specific models:
User:
attributes:
export: tables
columns:
Now it will only export the table definition and none of the foreign keys. You can use: none, tables, constraints, plugins, or all.
You are explicitly asking for data inconsistency, but I'm pretty sure you really don't want that. I can't think of a situation where this would be defensible. It is a bad practice and definitely will cause problems. For example: what is the expected result of $revision->getPage()?
There is a very simple and elegant solution: softdeletable. It basically adds an attribute to your entity (in other words: adds column to your table) named deletedAt to store if (or better: when) that entity is deleted. So if that attribute is null, the entity isn't deleted.
The only thing you have to do is add this bundle, add a trait to your entity (Gedmo\SoftDeleteable\Traits\SoftDeleteableEntity) and update your database. It is very simple to implement: this package will do the work for you. Read the documentation to understand this extension.
Alternatively, you can add an 'enabled' boolean attribute or a status field (for example 'published', 'draft', 'deleted').
When I delete the page I don't want to delete the revisions. I also want to keep the page_id on the page revisions (i.e. not set it to null).
I think you already got your answer: Doctrine won't do that, simply because it's alien to the notion of Foreign Keys. The principle of a FK is to ensure data consistency, so if you have a FK, it must refer to an existing ID. On delete, some DB engine such as InnoDB for MySQL allow you to put an FK to NULL (assuming you did made the FK column nullable). But referring to an inexistent ID is not doable, or it's not a FK.
If you really want to do it, don't use Doctrine for this specific case, it doesn't prevent you to use Doctrine elsewhere in your codebase. Another solution is to just drop the FK constraint manually behind or use a DB statement before your query to skip the FK checks.
I am trying to set a new field to my entity which is an array of booleans. I defined it like this:
/**
* #var bool[] $groupe_jours Selected days for the groups
* #ORM\Column(type="array")
*/
protected $groupe_jours;
I added the initialization in the constructor:
/** #ignore */
public function __construct()
{
$this->groupe_jours = array();
}
Now I want to make the migration
php app/console doctrine:migrations:diff
php app/console doctrine:migrations:migrate
This updates correctly the database:
ALTER TABLE licensee ADD groupe_jours LONGTEXT NOT NULL COMMENT '(DC2Type:array)'
However, when I try to reload my pages I get an error like this:
Could not convert database value "" to Doctrine Type array
This is because the array type requires a specific string when the array is empty, like: 'a:0:{}'
What is the best way to make sure that the migration updates the column correctly ?
Can I specify a default value for the migration
Can I put a default value in the field definition, that the migration should use ?
Should I update the database by hand ?
I sort of found an answer, but I am quite sure that there are better ones.
In the migration file that was created, in function public function up(Schema $schema), after:
$this->addSql('ALTER TABLE licensee ADD groupe_jours LONGTEXT NOT NULL COMMENT \'(DC2Typ
I added:
$this->addSql('UPDATE licensee SET groupe_jours = \'a:0:{}\'');
But I am quite sure that there are better solutions, as this one looks like a hack...
Suppose I have to set column value formula to 1. So how can I do it before persisting. After persisting I should get 1 in database.
$f=1;
$product->setFormula($f);
$em->persist($product);
If I use above line it gives an error
Expected value of type "Nimo\MrmdBundle\Entity\Product" for
association field "Nimo\MrmdBundle\Entity\Product#$basedOn", got
"integer" instead
Here is entity code
/**
* #ORM\ManyToOne(targetEntity="Product")
* #ORM\JoinColumn(name="formula", referencedColumnName="someothercolumn",nullable=true)
**/
private $formula = null;
You have to correct your entity definition first, However here's what you need to do in your controller. This will not work until you make sure your entities are correctly defined. (I can't because I don't know your entity definitions)
$f=1;
$em = $this->container->get('doctrine.orm.entity_manager');
$repo = $em->getRepository('AppBundle:Formula'); //This should be your referred entity
//You can also do findOneByName below
$formula= $repo->findOneById($id); //This should be the primary key of the referred entity NOT 1
$formula->setFormula($f);
$em->persist($formula);
When you are creating a relationship between two entities you can not pass a single value or variable containing a single value.
Entity works on objects. So try to pass the object of some entity or create an object with some value it will work. I also face the same error while passing a single value. Just pass the Object of an entity relationship annotation will picked up the joining column of other entity.
Can someone help pls? I am using doctrine_mongodb and I am trying to obtain the values of all keys in my document. I get the values of the fields with types integer, string and boolean but my fields of type hash return a value of 'null'
Here is how I define one of the hash fields in class Scripts of /documents/Scripts.php
/**
* #MongoDB\Document(collection="scripts")
*/
class Scripts
{
/**
* #MongoDB\Id
*/
public $id;
/**
* #MongoDB\Hash
*/
public $properties;
Thanks
I had the same issue. For me the Hydrator was cached with old values, and it wasn't referencing any of the new ones I added.
app/console cache:clear
app/console doctrine:mongodb:generate:documents BUNDLENAME
Solved my problem.
Fixed now. I manually created the hash type fields in "/var/www/Symfony/app/cache/dev/doctrine/odm/mongodb/Hydrators/AtlasMpBundleDocumentScriptsHydrator.php" with php type array. It is pretty easy to understand when you open the file.
Hope this helps someone :)
Functional test GH453Test.php in the ODM project includes an example of using a hash-mapped field. If you're seeing a null property after your model is hydrated, it is because the field does not exist or its value is null in the document returned from MongoDB. The conversion logic is rather straightforward in HashType::convertToPHPValue().