Set default to NULL with laravel migration - laravel

I am adding a field to a table in a migration that I wish to allow to be NULL but also I wish for it to default to NULL. What do I place in the default method? I fear that putting "NULL" in will attempt to place a string of NULLin which I obviously don't want. Please help :)
Schema::table('item_categories', function(Blueprint $table)
{
$table->integer('parent_item_category_id')->unsigned()->nullable()->default($what_to_put here);
});

When you use the nullable() method on a field, that field will default to NULL.
$table->integer('parent_item_category_id')->nullable();

To make the column "nullable", you may use the nullable method:
$table->string('email')->nullable();

Related

How to set a value in a null JSON column with Laravel's Eloquent?

I'm using Laravel 7.
I want to update a JSON column using Laravel's Eloquent. The problem is that if the value of the column is null the column won't be updated.
This is how the code looks like:
Model::update(['jsonColumnName->jsonColumnKey' => 'value']);
This is the SQL that it would generate:
UPDATE model
SET jsonColumnName = JSON_SET(jsonColumnName, '$.jsonColumnKey', 'value');
According to the documentation of JSON_SET, it will take the first parameter as the JSON document that it will modify. In this case, that value would be null since jsonColumnName is currently null. Because of that it returns null since it has nothing to modify and it ends doing nothing.
If I manually set the value of the column to {} and run the showed code, it works. But I guess that you are not expected to do that (right?).
You should make new alter table migration and change json column to have default value {}.
First you need to check if there is already installed dbal with
composer require doctrine/dbal
Then make new migration with code in up() method:
Schema::table('table_name', function (Blueprint $table) {
$table->json('column_name')->nullable()->default(null)->change();
});
Don't forget to backup database before work on it.
With NULL value you can also check if that field is empty.
Another way, on framework level is to set logic about this issue into model's observer.
For example:
public function saving(EntityModel $entityModel)
{
if (is_null($entityModel->json_column)) {
$entityModel->json_column = '{}';
}
}

Correct approach to making down migration for making column nullable type

I have a migration defined like so:
Schema::table('campaigns', function (Blueprint $table) {
$table->string('rates')->nullable(true)->change();
});
So I'm making "rates" nullable.
How should I handle the reverse migration? If there's no data in that column do I just set a default? I can't make it not null because that would violate integrity constraint. Can I not do anything about it?

How to change enum type column in laravel migration?

I am using Laravel 5.1 and I have a table called packages with this structure:
id int(11)
weight decimal(10,2)
weight_unit enum('Kg.', 'Gm.')
I would like to change the weight_unit enum to:
weight_unit enum('Grams','Kgs.','Pounds')
For this I create the following migration:
public function up()
{
Schema::table('packages', function ($table) {
$table->enum('weight_unit', array('Grams','Kgs.','Pounds'))->nullable()->change();
});
}
But when I run the migration I receive an error:
Unknown database type enum requested, Doctrine\DBAL\Platforms\MySqlPlatform
may not support it.
How can I change this enum?
Use the DB::statement method:
DB::statement("ALTER TABLE packages MODIFY COLUMN weight_unit ENUM('Grams', 'Kgs', 'Pounds')");
This worked for me when adding a new enum value to the modified enum column.
Add the following to the up() method:
DB::statement("ALTER TABLE packages MODIFY weight_unit ENUM('Grams', 'Kgs', 'Pounds', 'new value') NOT NULL");
Then in the down() method you can revert the change that was made:
DB::statement("ALTER TABLE packages MODIFY weight_unit ENUM('Grams', 'Kgs', 'Pounds') NOT NULL");
Note: before the enum value is removed it needs to be changed to another enum value that will be retained.
$table->enum('level', ['easy', 'hard']);
You can add custom constructor to migration and explain to Doctrine that enum should be treated like string.
public function __construct(\Doctrine\DBAL\Migrations\Version $version)
{
parent::__construct($version);
$this->platform->registerDoctrineTypeMapping('enum', 'string');
}
In case you dont want to lose your data and update it with the new values I came up with this solution:
// Include old and new enum values
DB::statement("ALTER TABLE packages MODIFY COLUMN weight_unit ENUM('Kg.', 'Gm.', 'Grams', 'Kgs', 'Pounds')");
// Replace Kg. with Kgs
Packages::where('weight_unit', 'Kg.')->update(['weight_unit' => 'Kgs']);
// Replace Gm. with Grams
Packages::where('weight_unit', 'Gm.')->update(['weight_unit' => 'Grams']);
// Delete old values
DB::statement("ALTER TABLE packages MODIFY COLUMN weight_unit ENUM('Grams', 'Kgs', 'Pounds')");
This way you can replace your old values with the new ones.
add this before change() call :
DB::getDoctrineSchemaManager()->getDatabasePlatform()->registerDoctrineTypeMapping('enum', 'string');
I think that is fixed on Laravel 10 by adding support for native column modifying.
https://github.com/laravel/framework/pull/45487
So from Laravel 10 you can do this:
Schema::table('jobs', function (Blueprint $table) {
$table->enum('type', ['contract', 'permanent', 'partial'])->change();
});
I tried the same migration on fresh Laravel 9.55.0 and 10.0.2 application:
laravel-9.52.0.jpg
laravel-10.0.2.jpg
I am able to solve this by removing and adding constraints. This has made sure that my existing data is also is intact.
DB::statement("ALTER TABLE purchases DROP CONSTRAINT purchases_ref_check");
$types = ['single', 'monthly', 'biannual', 'amount', 'other'];
$result = join( ', ', array_map(function( $value ){ return sprintf("'%s'::character varying", $value); }, $types) );
DB::statement("ALTER TABLE purchases add CONSTRAINT purchases_ref_check CHECK (ref::text = ANY (ARRAY[$result]::text[]))");
with default value. add this in up():
\DB::statement("ALTER TABLE `patient_appointments` CHANGE `status` `status` ENUM('pending','wait','approved', 'consulted') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'pending';");

Laravel Schema Builder, setting field description

Is it possible to add a description/comment to the sql field with laravel's schema builder. Just like in drupal?
It turns out that you can add comments, but it doesn't seem to be documented. This Laracasts post shows how – by adding a "comment" property to the end of the line.
Using their example,
Schema::create('products', function(Blueprint $table)
{
$table->increments('id');
$table->string('product_name')->comment = "Product name column";
$table->timestamps();
});
}
As it turns out – just testing now – you can actually use the more typical function syntax for that, so for example,
$table->string('product_name')->comment('Product name column');
...similar to setting ->default(...) or ->nullable(). Some people might prefer that style for consistency.
This seems to work great as of Laravel 5 and using MySQL. It might be a recent improvement.
Descriptions / comments are not supported by the schema builder and probably won't in the future. You have to fall back to SQL:
Assuming you use MySQL
Schema::create('users', function(Blueprint $table){
$table->increments();
$table->text('username');
$table->text('password', 60);
});
DB::statement('ALTER TABLE `users` CHANGE `password` `password` VARCHAR(60) COMMENT 'password hash');

Laravel Schema Builder Update Default Value

Trying to setup a migration that will make my already existing "active" field have a default value of "1".
I see in the docs I can use something like:
$table->integer('active')->default(1);
But I tried this in my migration with no success, I guess because the field already exists. Is there a way to correctly manage existing fields using the schema builder?
My current migration:
public function up()
{
Schema::table('scores', function($table){
$table->integer('active')->default(1);
});
}
Edit:
From what I've read so far, this can't be done with the query builder. But when I try to run a raw query:
DB::query("ALTER TABLE `scores` CHANGE COLUMN `active` `active` int(11) NOT NULL DEFAULT '1';");
I'm getting a "method 'query' does not exist error", so I'm guessing this method name was changed I just can't find what it was changed to
Looks like DB::query() was changed to DB::statement()
This did the trick:
DB::statement("ALTER TABLE `scores` CHANGE COLUMN `active` `active` int(11) NOT NULL DEFAULT '1';");

Resources