As I understand, mutators change your attribute on save function (create or update). Can I make mutator just for atrribute display to users, but leave default values on save function ?
In Eloquent Model when you do this:
public function getSomeNameAttribute($value)
{
return ucfirst($value);
}
That ^ will mutate the value for showing it later in views and it won't affect what is stored in DB table.
And also if you use a setter setSomeNameAttribute($value) you can pull the actual value from db table with:
$model->getOriginal('attribute_name'); // Laravel V. ^5.*
or
$model->getRawOriginal('attribute_name'); // Laravel V. ^8.*
I have two entities:
Person, which has workspace_id column
PersonRevision, which does not have workspace_id column
In a migration I have this:
$persons = Person::all();
foreach ($persons as $person) {
$revision = new PersonRevision;
$revision->fill($person->getAttributes());
$revision->save();
}
PersonRevision does not have workspace_id in fillable property. But for some reason I got an error: column "workspace_id" of relation "person_revisions" does not exist.
Besides, if I run the migration second time (by just typing php artisan migrate second time) it works fine.
What could be the reason? I know I can manually list attributes which need to be filled, or use array_except but this is inconvenient and does not answer why that happens.
Could you check what the actual sql statement is that's executed? To me it seems like you have a database which does not contain workspace_id yet, but your model does expect it to be there. Even when not filling the workspace_id the query generated from your eloquent model will probably try to update it with the value null, which it can't do if it's not there.
Because of issues like this it's best not to use eloquent models in database migrations, instead use raw sql.
Laravel SeedCommand handle() function runs with Model::ungarded() which forces all props to be fillable. When unguarded is true it auto fills regardless of fillable array.
public function isFillable($key)
{
if (static::$unguarded) {
return true;
}
[...]
}
Simply add this atop your seeder file Model::reguard();
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
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';");
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();