Renaming a column in a migration script in Doctrine2 - php

When I have a Table reference and I call renameColumn() on it, I get the following pair of errors:
Migration 20130725141653 failed during Execution. Error Table#renameColumn() was removed, because it drops and recreates the column instead. There is no fix available, because a schema diff cannot reliably detect if a column was renamed or one column was created and another one dropped.
[Doctrine\DBAL\DBALException]
Table#renameColumn() was removed, because it drops and recreates the column instead. There is no fix available, because a schema diff cannot reliably detect if a column was renamed or one column was created and another one dropped.
(executed via doctrine migrations:migrate --dry-run)
Which makes sense... for a diff program.
I'm writing a migration. I know that I want the column renamed (preserving data).
Is there any pure Doctrine method (I don't want to write a raw query) to acheive this?

The 'diff' that the exception is talking about is the diff between your original Schema and your updated Schema. This is how Doctrine generates the SQL statements -- by comparing the current Schema to the modified Schema.
There is no way for Doctrine to reliably figure out that someColumn in $originalTable is now someRenamedColumn in $modifiedTable (pardon the bad psuedocode) and so the functionality was removed .

Related

Alias table column values in laravel?

I'm converting an older system to laravel/eloquent and I'm still somewhat new to all the 'toys' built in to the ORM. Often I code out something and find out something like it already exists in the back-end code.
What I have is a table of records where the 'name' field has either changed spelling over time, it is occasionally abbreviated, gets changed in API input or is frequently mis-spelled in manual input. (I'm not entirely sure which of the four is the reasoning) So it utilizes additional records and columns to deal with the alternate names and abbreviations.
I would usually code this sort of thing with a second 'aliases' table for the alternate/abbreviated variations pointing back to the primary (proper) named record in the main table. If it's not found by the exact name, check the 'aliases' table and return the record it points to.
Before I code a getByName() set of methods and overrides to some of the standard model methods, I'm wondering if there is anything built in that might already handle this. (I'm aware I could set up a second table with a many-to-one relationship just for names - I'm just wondering if there's anything else hiding out there)

How to add a column after another column in sqlite using Laravel migrations?

Is there a method in Laravel 5.4 to add a column after/before another column inside a sqlite table? Like after('column') for MySql?
Why I'm in a hurry is because whenever I tried to rename a column using Laravel migration, it jumps and stick to the last / end of a table!
Is there a way to get rid out of this?
Short answer: no.
However there is apparently a workaround:
Insert new column into table in sqlite?
Disclaimer: I rarely use sqlite and cannot verify this works. Good luck.

Laravel PHPUnit failing on ALTER TABLE using SQLite

I have a migration which I made at the beginning of my project, basically adding a TEXT column called 'description' which is set to NOT NULL.
Now several months down the track I need to change that to allow null.
I can't use Laravel 5.5 change() function as I have a enum in my column list and it bugs out, so i need to add it as a raw query in a migration like so;
DB::statement('ALTER TABLE `galleries` MODIFY `description` TEXT NULL;');
When i do a php artisan migrate against my local mysql database it all works great, BUT when i try to run my test suite, it all breaks.
Im using SQLite for my test suite, and the error im getting is as follows;
PDOException: SQLSTATE[HY000]: General error: 1 near "MODIFY": syntax error
If anyone else has come up against this issue and fixed it, i would love to hear how you did it.
Thanks
SQLite only allows you to rename the table or add a column. The ALTER TABLE statement cannot change or remove columns.
In order to change or remove a column in SQLite, you need to create a new table with the desired schema, copy the data from the original table to the new table, delete the original table, and then rename the new table to the original name.
This is all abstracted out for you by Laravel and DBAL, so your best bet may be to get help with figuring out the issue with your enum column (though that would be a separate question).
You can read more about altering tables in the SQLite docs here.

Updating same query repeatedly in database generation

I have generated entities from a (MySQL) database, then created a new (zf2) project with a blank database by running the following statements:
vendor/bin/doctrine-module orm:schema-tool:create
vendor/bin/doctrine-module orm:schema-tool:update --force
vendor/bin/doctrine-module orm:validate-schema
Unfortunately the update statement keeps updating the same statement:
ALTER TABLE rollen CHANGE name name VARCHAR(30) NOT NULL;
and the validation fails. The DB shows the correct column. The Doctrine\DBAL\Schema\Comparator shows a different precision (not yet quite sure what that is supposed to be) of the corresponding column.
Some related questions did not seem to fit or work.
Looking at the corresponding diffColumn function in Doctrine\DBAL\Schema\Comparator, showed me that auto-increment set in the meta-data schema (see following annotation):
#ORM\GeneratedValue(strategy="IDENTITY")
the precision part seems to be part of this strategy (although I still don't understand this, since a auto-increment id is rather an in than decimal, see http://doctrine-orm.readthedocs.org/en/latest/reference/annotations-reference.html#column)

Dump MySQL CREATE TABLE for whole schema including foreign keys (creating order)

What I would like to 'have' is someway to export my tables including the foreign keys. And whenever/whereever re-execute those create table queries.
The problem I am facing though is making sure the right preconditions exist per table.
if table B references A and A references C. Then first C must be created, then A and at last B.
But creating the right order is something that I do not know how to do (yet).
I am currently creating the queries this way: (not the complete code)
class DBManager{
private function createSQLCreateTableDump(){
$query = "SHOW TABLES";
$res = $this->db->prepare($query)->fetchObjectAll();
foreach( $res as $table){
$this->createSQLCreateTableQuery(current(get_object_vars($table)));
}
}
private function createSQLCreateTableQuery($tableName){
$query = "SHOW CREATE TABLE {$tableName}";
$res = $this->db->prepare($query)->fetchObjectOnce();
return $res->{"Create Table"};
}
}
As a reference, $this->db is a class named Database which extends PDO.
fetchObjectOnce and fetchObjectAll returns each row returned as an object. The first argument (which I am not using here) specifies the class type returned. Else stdClass is used.
current(get_object_vars($table)) is used to get the first column returned. Because the column names differ per database used. This seemed the fastest/easiest way.
The problem with this method is that some tables with constraints will be created before the constraint can be created.
the question: What would be a good solution to this problem?
Just thought of this: (which I will try to work out).
I can get the constraints themself from the informatino_schema.table_constraints and key_column_usage tables. Thus I can create a tree of dependancies. Will see how far I can come that way.
The best way of doing this is to invoke mysqldump, which does exactly what you suggested.
If for some reason, you feel that you can't invoke mysqldump (which is typically installed on all mysql client systems), then you can inspect its source and determine how it does it.
As far as I know, mysqldump disables foreign keys while doing some operations, to avoid dependencies during table creation.
Recreating the behaviour of mysqldump is nontrivial and difficult to do correctly, I strongly advise you to invoke mysqldump instead.
Right, I've answered my own question and provided an example:
http://pastebin.com/5dg6B0ZF
it is not the cleanest of my work, but it works so far.
it creates two temporary arrays.
One holding the references per table, the other the queries.
I am using table names as keys for the arrays for easy searching.
I won't accept my own answer till somewhere tomorrow to see if someone else comes up with a better solution.
Let me know what you think.

Categories