Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

rezafm's avatar

all columns nullable vs. disable ConvertEmptyStringsToNull

Hello,

I am a bit stuck with one question.

As you know, Laravel converts empty strings to null values by passing them through the ConvertEmptyStringsToNull Middlewae.

I have a few models for which I want to offer an auto-saving feature. This means on "creation" I create a model and then redirect to the edit page immediately (so the creating form is never shown).

If I now have a Post Model with some mandatory columns like (not nullable):

  • Title
  • slug

and optional columns like (all nullable):

  • content
  • meta_description

et cetera.

Then I run into an issue on creation when I do the following:

Post::create([
  'title' => ''
  'slug' => ''
])

Because I will be told that these columns cannot be null - that is to be expected, as the mentioned Middleware will convert the empty strings to NULL values.

Did anybody come across this issue and has some best practice to share?

I mean, of course I could offer a default slug, such as "Auto Draft" or something.

Alternatively, I could disable the Middleware, but then I also need to have to write several Mutators for the fields I want to make sure they are nullable.

And of course, I could just make all fields nullable, including the mandatory title and slug fields, but I question if that's the right way actually?

I hope that makes sense and would appreciate any feedback.

0 likes
8 replies
MohamedTammam's avatar

There's no issue when you do

Post::create([
  'title' => ''
  'slug' => ''
])

The string will be converted to null when it's being sent with a request from the user.

kokoshneta's avatar

@MohamedTammam That is exactly the problem: they will be converted to null, which means the insert/update will fail, because the fields are not nullable.

1 like
rezafm's avatar

Hi Mohamed,

well, the issue is, that these columns are supposed to be NOT NULLABLE, so the database won't let me save them.

kokoshneta's avatar

If you want to make it possible to auto-save a model periodically even though the user has not entered any data at all into any fields, you have little choice but to make everything nullable.

Otherwise, you have to define the logic that determines when the model is auto-saved, skipping the save if required fields are empty.

1 like
rezafm's avatar

Hi, Thanks for helping out here.

Actually, it is quite inspired by the way wordpress does it. So, when you hit the "Create"-Button a new entry is pushed into the database with the status "auto-save".

Then every 60 seconds the content is checked for being changed, if this is the case, the status is updated to "draft" (when it was auto-save before) and also the content field is updated. That's it.

Actually, works pretty well, the only thing that is worrying me is to make all columns to nullable just to have one model that can be used for auto-saving, like

        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->unsignedBigInteger('site_id')->index();
            $table->unsignedBigInteger('draft_id')->nullable()->index();
            $table->string('title')->nullable();
            $table->string('slug')->nullable()->index();
            $table->string('status')->default('draft');
            $table->longText('content')->nullable();
            $table->text('excerpt')->nullable();
            $table->string('headline')->nullable();
            $table->string('keyword')->nullable();
            $table->boolean('featured')->default(false);
            $table->boolean('show_title')->default(true);
            $table->string('image')->nullable();
            $table->text('meta_description')->nullable();
            $table->string('meta_title')->nullable();
            $table->string('meta_robots')->nullable();
            $table->bigInteger('order')->default(0);
            $table->text('scripts')->nullable();
            $table->timestamps();
            $table->timestamp('published_at')->nullable()->useCurrent();

            $table->index(['site_id', 'slug']);
            $table->foreign('site_id')->references('id')->on('sites')->onDelete('cascade');
            $table->foreign('draft_id')->references('id')->on('posts')->onDelete('cascade');
        });

I mean, it is not the end of the world to have these fields not nullable:

            $table->string('title')->nullable();
            $table->string('slug')->nullable()->index();

But it seems like, as you said, I don't really have a choice then, unless I don't want to disable the Middleware.

rezafm's avatar
rezafm
OP
Best Answer
Level 1

Okay, as always, just after you asked your question you stumble across something, so let's say we have a Post table as mentioned:

        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->unsignedBigInteger('site_id')->index();
            $table->unsignedBigInteger('draft_id')->nullable()->index();
            $table->string('title');
            $table->string('slug')->nullable()->index();
            $table->string('status')->default('draft');
            $table->longText('content')->nullable();

            $table->unique(['site_id', 'slug']);
            $table->foreign('site_id')->references('id')->on('sites')->onDelete('cascade');
            $table->foreign('draft_id')->references('id')->on('posts')->onDelete('cascade');
        });

Then to save an empty string (which will just be empty for a very short time until the user has put in something), the workaround is as simple as:

    public function setTitleAttribute($value)
    {
        $this->attributes['title'] = is_null($value) ? '' : $value;
    }

Having the slug column to be NULL is also in line with the excellent Sluggable package (https://github.com/cviebrock/eloquent-sluggable), and also helps to be able to do the following:

$table->unique(['site_id', 'slug']);

Because if we add empty strings to the slug column (instead of NULL), the database will freak again out, if you want to add a model that has an empty slug.

Well, well....

Please or to participate in this conversation.