2

I am facing a very strange behavior in my laravel application. I am using observers to perform my business model logic e.g. saving images which are base64 encoded within the content provided by a textfield to my server and replace them with an image link. However, that's not the problem at all. The problem is that my observer gets a empty model passed.

First I thought this is a problem which has something to do with Laravel Nova, because this is where I edit my content for my posts. But it doesn't. I have written a very simple example which is doing exactly the same and facing the same problem as well. You can edit the content of a post on a page within an editor, submit this page via a post request form and the content gets saved as the new content. So far so good, everything works fine. Even the content gets saved correctly in the database and is shown correctly on the fronted. Also my updating event gets fired and triggered and the lines within my observer get executed. I do know that because I write a few lines to the log within the code of my updating event in the observer.

But, the problem is that the model the updating function gets passed over is empty and I cannot explain myself why. But it is only sometimes empty. I couldn't figure out yet when it is empty. Maybe someone of you guys can explain me why the model is empty. I need to access my model before it is being saved to the database. How can I do this?

I am using PHP 8.0.3 and Laravel v8.47.0.

And yes, I have also registered my Observer in my AppServiceProdiver. Otherwise the log wouldn't be filled.

With the following code you can reproduce the problem:

Migration

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreatePostsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->increments('id');        
            $table->char('heading')->index();
            $table->char('slug')->index();
            $table->text('content');
            $table->integer('views')->default(0);
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('posts');
    }
}

Model

<?php

namespace App\Models;

class Post extends Model 
{
    /**
     * @Protected_variables
     */

    protected $table = 'posts';

    protected $guarded = ['id'];
}

PostController

<?php

namespace App\Http\Controllers;

use App\Models\Post;

class PostController extends Controller
{
    public function edit(Post $post)
    {
        return view('pages.postEdit', ['post' => $post]);
    }

    public function update(Post $post, Request $request)
    {
        $post->content = $request->input('content');
        $post->save();

        return redirect()->back();
    }
}

Routes

Route::get('/posts/{post:id}/edit', ['as' => 'post.edit', 'uses' => 'PostController@edit']);

Route::post('/posts/{post:id}/edit', ['as' => 'post.edit', 'uses' => 'PostController@update']);

Blade File

<form method="POST" action="/posts/{{ $post->id }}/edit">
    @csrf
    <textarea name="content" cols="100" rows="10">{{ $post->content }}</textarea><br>
    <button type="submit">Submit Post</button>
</form>

In the following code you can see that I log my event and try to log my model I get passed. However, the model is just empty. When I try to access the model, I get an error and when I try to log it its just empty. I even tried var_export and json_decode. Nothing works... But as the model is an object is can also be echoed directly. However, the echo is empty.

The two lines below are saving my base64 encoded images to the server and so on. They need to access the model.

Observer:

<?php

namespace App\Observers;

use App\Models\Post;

class PostObserver
{
    /**
     * Handle the Post "updating" event.
     *
     * @param  \App\Models\Post  $post
     * @return void
     */
    public function updating(Post $post)
    {
        \Log::warning("Updating");
        \Log::warning("Info model: " . $post); // <--- This line echos nothing except 'Info model: '

        //checkExistingImagesAndDeleteWhenNotFound($post, request()->input('content'), 'post_content_images', 'medium');
        //$post->content = addBase64ImagesToModelFromContent($post, request()->input('content'), $images, 'post_content_images', 'medium');
    }
}
yivi
  • 42,438
  • 18
  • 116
  • 138
Jan
  • 1,180
  • 3
  • 23
  • 60
  • `$post` is not a string so it would execute the `__toString` method which (if I recall correctly) does not do much for models. What's the output of `"Info model: ".json_encode($post)`? – apokryfos Jun 24 '21 at 08:25
  • 1
    @apokryfos `Model::__stoString()` [does exactly that](https://github.com/laravel/framework/blob/78eb4dabcc03e189620c16f436358d41d31ae11f/src/Illuminate/Database/Eloquent/Model.php#L1638). – yivi Jun 24 '21 at 08:32
  • I already tried `json_encode` and also `var_export`. Leads to the same problem... Sometimes the model is empty, sometimes not. – Jan Jun 24 '21 at 08:34

0 Answers0