In CakePHP3 migrations (or Phinx), how to use utf8mb4 charset? - cakephp-3.x

Creating MySQL table or adding columns with CakePHP3 migrations, charset is set to UTF8.
Is there the way to set charset utf8mb4?
(and, i found this issue... https://github.com/robmorgan/phinx/issues/74)

You can set the collation when you call the table() function.
public function change() {
$table = $this->table('FooBar',['collation'=>'utf8mb4_unicode_ci']);
//.....
}
You can only set the collation type. The character set will be extracted from that collation string. There for the above will have a character set of "utf8mb4".

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 = '{}';
}
}

How store null in database using vue and laravel?

I have Vue project with Laravel API, and also I have a column named expired_date: date it is nullable
this is the response after I dd the data from the network console:
The problem is when I store the data I just found the expired_date store value 0000-00-00
My code of store:
$data = $request->except('image');
if (!$request->expired_date) {
$data['expired_date'] = null;
}
Post::create($data);
The issue is that an empty string '' is being saved instead of null, resulting in 0000-00-00 values saved to the field. In this case it's because the ConvertEmptyStringsToNull middleware included with the framework was mistakenly commented out and disabled, so the solution is to re-enable that middleware.
Other common causes are forgetting to make the field nullable in the database, or having an incorrect default value.
To explicitly set a field to null without using the ConvertEmptyStringsToNull middleware, it is possible to use a mutator similar to this inside of the model:
public function setExpiredDateAttribute($date) {
$this->attributes['expired_date'] = empty($date) ? null : Carbon::parse($date);
}

Time format of database field, help needed

Time is stored in my database as H:i:s format for a timefield.
When I query I want time returned as hours:minutes without the seconds part.
I tried to set the "protected $dateFormat " setting using a Mutator. Can anyone show an example of the dateFormat setting needed? The database must remain hour:minute:seconds time settings, only the retrieved value needs to be changed for display.
protected $dateFormat = 'Y-m-d H:i:s'; // ?
One way to solve it is to treat dates as Carbon instances. The format to save on database will be auto-converted and you should use in any format.
protected $dates = [
'field_name'
];
https://laravel.com/docs/5.8/eloquent-mutators#date-mutators
// converting db column name time_match into the function as getTimeMatchAttribute worked for me.
public function getTimeMatchAttribute($value){
return date('H:i',strtotime($value));
}
you can make it with getters function in your model
like this:
public function getTimeAttribute($time){
return date('h:i',strtotime($time))
}
Time in function name should be your column name in upper case

How to get the default MySql values in `firstOrNew` in Laravel?

If I use firstOrCreate then the default values are given for the model that I set up in the database. But when I use firstOrNew the values are not given and are instead given out as NULL. Is there any way to fix this aside from using firstOrCreate?
This is because firstOrNew will just create a new instance of your model when it doesn't get a result from the database. Therefore it does not get the default values from the database.
So I guess you have at least two options here. The first one would be the one you already mentioned using firstOrCreate (this is not something I would recommend because this could lead to incorrect state in your database). Another option would be to add 'Accessorson your model with which will return either the value retrieved from the database or when it'snull` it will return the default value you define.
public function getMyFieldAttribute($myField)
{
if ($myField === null) {
return 'my-default-value';
}
return $myField;
}
More info on accessors can be found in the documentation: https://laravel.com/docs/5.2/eloquent-mutators#accessors-and-mutators

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';");

Resources