为什么Eloquent在插入数据库时​​没有看到模型中的所有字段

为什么Eloquent在插入数据库时​​没有看到模型中的所有字段

问题描述:

I'm new to Laravel development and am trying to create an Eloquent model backed by an SQLite database. I have the following code on my local development server, which correctly takes a request, builds a model, and saves that model as a row in the callback_requests table.

Below is the model definition file and the database migration file. I've run the migration using

php artisan migrate:reset --force
php artisan migrate 

CallbackRequest.php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class CallbackRequest extends Model
{
    public $name;
    public $phone;
    public $email;
    public $preferredTime;
}

create_callback_requests_table (migration).php

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

class CreateCallbackRequestsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('callback_requests', function (Blueprint $table) {
            $table->increments('id');
            $table->timestamps();
            $table->string('phone');
            $table->string('email');
            $table->string('preferredTime');
            $table->string('name');
        });
    }

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

This is the controller file where I create a new instance of my model, populate it with values from an incoming request, and save it to the DB.

MailController.php

namespace App\Http\Controllers;

use App\Models\CallbackRequest;
use App\Mail\CallbackRequestMailable;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Mail\Mailable;
use Illuminate\Support\Facades\Mail;

class MailController extends Controller
{
    public function send(Request $request) 
    {
        $cbReq = new CallbackRequest();
        $cbReq->name = $request->get('name');
        $cbReq->email = $request->get('email');
        $cbReq->phone = $request->get('phone');
        $cbReq->preferredTime = $request->get('preferredTime');
        var_dump($cbReq);
        // save the entity to the database in case mail gets lost in transit
        $cbReq->save();
        // send an email to the address configured in the .env file
        $result = Mail::to(env("MAIL_CALLBACK_DELIVERY_ADDRESS"))->send(new CallbackRequestMailable($cbReq));
    }
}

I've dumped the contents of the $cbReq variable to make sure that values have been added correctly, and the output I get (shown below) suggests that they have

object(App\Models\CallbackRequest)#222 (30) {
  ["name"]=>
  string(13) "Customer Name"
  ["phone"]=>
  string(9) "012345678"
  ["email"]=>
  string(14) "cust@email.com"
  ["preferredTime"]=>
  string(7) "morning"
  ["connection":protected]=>
  NULL
  ["table":protected]=>
  NULL
  ["primaryKey":protected]=>
  string(2) "id"
  ["keyType":protected]=>
  string(3) "int"
  ["incrementing"]=>
  bool(true)
  ["with":protected]=>
  array(0) {
  }
  ["withCount":protected]=>
  array(0) {
  }
  ["perPage":protected]=>
  int(15)
  ["exists"]=>
  bool(false)
  ["wasRecentlyCreated"]=>
  bool(false)
  ["attributes":protected]=>
  array(0) {
  }
  ["original":protected]=>
  array(0) {
  }
  ["changes":protected]=>
  array(0) {
  }
  ["casts":protected]=>
  array(0) {
  }
  ["dates":protected]=>
  array(0) {
  }
  ["dateFormat":protected]=>
  NULL
  ["appends":protected]=>
  array(0) {
  }
  ["dispatchesEvents":protected]=>
  array(0) {
  }
  ["observables":protected]=>
  array(0) {
  }
  ["relations":protected]=>
  array(0) {
  }
  ["touches":protected]=>
  array(0) {
  }
  ["timestamps"]=>
  bool(true)
  ["hidden":protected]=>
  array(0) {
  }
  ["visible":protected]=>
  array(0) {
  }
  ["fillable":protected]=>
  array(0) {
  }
  ["guarded":protected]=>
  array(1) {
    [0]=>
    string(1) "*"
  }
}

However, when the app encounters an error on save giving the following message.

{
    "message": "SQLSTATE[HY000]: General error: 1364 Field 'phone' doesn't have a default value (SQL: insert into     `callback_requests` (`updated_at`, `created_at`) values (2019-03-11 10:19:24, 2019-03-11 10:19:24))",
    "exception": "Illuminate\\Database\\QueryException",
    ...
}

It looks from the error message as if Eloquent doesn't know about the custom columns, and is trying to populate only the auto-increment ID and timestamp. Strangely, when I run this same code on my local server, everything works OK, it's only when the code is deployed to a testing server that I'm encountering the error.

Apologies for the lengthy question, I've tried to include as little as possible while not omitting anything relevant. Any suggestions would be greatly appreciated.

You need to delete your properties from the model. So delete all of these:

public $name;
public $phone;
public $email;
public $preferredTime;

Otherwise when you set $model->phone = $request->phone, it sets this property on your object instead of setting the key in the model's $attributes array, which is what gets saved to the database.

This is due to Laravel hooking the PHP magic method __set() to set attributes of models. This is what's inside the base Model class:

/**
 * Dynamically set attributes on the model.
 *
 * @param  string  $key
 * @param  mixed  $value
 * @return void
 */
public function __set($key, $value)
{
    $this->setAttribute($key, $value);
}

If you had those properties for your IDE's IntelliSense (auto completion), you can still use a docblock to hint the dynamic properties:

/**
 * Class CallbackRequest
 *
 * @property-read string name
 * @property-read string phone
 * @property-read string email
 * @property-read string preferredTime
 */
class CallbackRequest extends Model {}

or use a package like Laravel IDE helper to automate this step.