новая модель заполняет updated_at - PullRequest
0 голосов
/ 17 июня 2020

Я использую Lumen и только что обнаружил проблему. При создании новой модели код также заполняет «updated_at», несмотря на то, что модель новая и еще не обновлялась (поскольку была только что создана). Поскольку это серьезный недостаток, и было бы странно, если бы он не был замечен до сих пор, я предполагаю, что делаю что-то не так.

App \ User. php:

<?php
namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    const CREATED_AT = 'date_created';
    const UPDATED_AT = 'date_updated';

    protected $fillable = [
        'name',
        'email',
        'role_id',
        'password'
    ];

    protected $hidden = [
        'token',
        'password',
        'date_password_reset',
        'token_password_reset'
    ];

    protected $casts = [
        'date_created' => 'datetime:Uv',
        'date_updated' => 'datetime:Uv',
        'date_password_reset' => 'datetime:Uv'
    ];

    protected $with = ['userRoles'];

    protected $validationRules = [...];
}

App \ Http \ Controllers \ UsersController. php:

<?php
namespace App\Http\Controllers;

use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use App\User;
use Illuminate\Validation\ValidationException;
use Exception;

class UsersController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');
    }

    ...

    // first attempt
    public function create(Request $request) {
        $this->validate($request, (new User)->rules('create'));

        $user = new User;
        $user->name = $request->input('name');
        $user->email = $request->input('email');
        $user->password = Hash::make($request->input('password'));
        $user->role_id = $request->input('role_id');
        $user->active = $request->boolean('active');
        $user->save();

        return response()->json(
            [
                'success' => true,
                'message' => 'User successfully created',
                'data' => User::query()->find($user->id)
            ], 200);
    }

    // second attempt
    public function create(Request $request) {
        $this->validate($request, (new User)->rules('create'));

        $user = new User;
        $user->update($request->input());
        $user->password = Hash::make($request->input('password'));
        $user->active = $request->boolean('active');
        $user->save();

        return response()->json(
            [
                'success' => true,
                'message' => 'User successfully created',
                'data' => User::query()->find($user->id)
            ], 200);
    }

    // third attempt
    public function create(Request $request) {
        $this->validate($request, (new User)->rules('create'));

        $user = new User($request->input());
        $user->password = Hash::make($request->input('password'));
        $user->active = $request->boolean('active');
        $user->save();

        return response()->json(
            [
                'success' => true,
                'message' => 'User successfully created',
                'data' => User::query()->find($user->id)
            ], 200);
    }
}

Миграция БД:

<?php

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

class CreateUsersTable extends Migration
{
    protected $initialUsers = [
        [
            'name' => 'Administrator',
            'email' => 'admin@localhost.local',
            'password' => null,
            'role_id' => null,
            'active' => 1
        ]
    ];

    protected $initialRoles = [
        [
            'name' => 'Administrator'
        ],
        [
            'name' => 'User'
        ]
    ];

    protected $initialUserRoles = [];

    public function up()
    {
        DB::beginTransaction();;

        Schema::create('users_roles', function (Blueprint $table) {
            $table->id();
            $table->string('name', 50);
            $table->timestamp('date_created')->useCurrent();
            $table->timestamp('date_updated')->nullable()->default(DB::raw('NULL ON UPDATE CURRENT_TIMESTAMP'));
        });

        foreach ($this->initialRoles as $data) {
            DB::table('user_roles')->insert($data);
        }

        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('name', 100);
            $table->string('email', 255)->unique();
            $table->string('password');
            $table->unsignedBigInteger('role_id')->nullable();
            $table->string('token', 255)->nullable();
            $table->tinyInteger('active');
            $table->timestamp('date_password_reset')->nullable();
            $table->string('token_password_reset')->nullable();
            $table->timestamp('date_created')->useCurrent();
            $table->timestamp('date_updated')->nullable()->default(DB::raw('NULL ON UPDATE CURRENT_TIMESTAMP'));

            $table->foreign('role_id')->references('id')->on('users_roles')->onDelete('set null')->onUpdate('cascade');
        });

        $password = Hash::make('xxx@x');
        $role_id = DB::table('users_roles')->where('name', 'Administrator')->value('id');
        foreach ($this->initialUsers as $data) {
            $data['password'] = $password;
            $data['role_id'] = $role_id;
            $user_id = DB::table('users')->insertGetId($data);

            $this->initialUserRoles[] = [
                'user_id' => $user_id,
                'role_id' => $role_id
            ];
        }

        DB::commit();
    }
}

Запрос, созданный Eloquent:

array (size=3)
      'query' => string 'insert into `users` (`name`, `email`, `password`, `role_id`, `active`, `date_updated`, `date_created`) values (?, ?, ?, ?, ?, ?, ?)' (length=131)
      'bindings' => 
        array (size=7)
          0 => string 'Test User 5' (length=11)
          1 => string 'test6@test.net' (length=14)
          2 => string '$2y$10$lvRGKuznotd8lqwCj2diIONGjyiAkhaNthWGjQyFWbBqiyuf20wpG' (length=60)
          3 => string '1' (length=1)
          4 => boolean true
          5 => string '2020-06-17 10:30:07' (length=19)
          6 => string '2020-06-17 10:30:07' (length=19)
      'time' => float 5.5

Все три create() попыток заполняют "updated_at", несмотря на то, что он должен оставаться NULL, пока не будет выполнено фактическое обновление этой модели. Вы, ребята, можете указать мне, что я делаю не так? Также хотелось бы сохранить функциональность $model->update($request->input()), если это возможно, чтобы мне не приходилось назначать каждое поле вручную.

1 Ответ

0 голосов
/ 17 июня 2020

Поскольку Lumen / Laravel самостоятельно обрабатывает поля created_at и updated_at и устанавливает для них одну и ту же временную метку при создании записи (что мне не нравится), я создал свое собственное решение.

Первый уже используется при создании миграции. Я создал свои собственные поля меток времени, и они уже правильно обновлены MySQL:

$table->timestamp('date_created')->useCurrent();
$table->timestamp('date_updated')->nullable()->default(DB::raw('NULL ON UPDATE CURRENT_TIMESTAMP'));

И, конечно же, отключил обработку меток времени для Lumen в модели User.php:

public $timestamps = false;

Но в случае, если это невозможно по какой-либо причине или если вы хотите, чтобы Lumen / Laravel обрабатывал их, это код, который я написал в модели User.php:

const CREATED_AT = 'date_created';
const UPDATED_AT = 'date_updated';

public $timestamps = false;

public static function boot() {
    parent::boot();

    static::creating(function ($model) {
        $model->{self::CREATED_AT} = $model->freshTimestamp();
    });
    static::updating(function ($model) {
        $model->{self::UPDATED_AT} = $model->freshTimestamp();
    });
}
...