1

I have a ‘recurring_payments’ table

Schema::create('recurring_payments', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('user_id');
            $table->string('card_id');
            $table->string('day');
            $table->integer('amount');
            $table->timestamps();
        });

I have a ‘card’ table

Schema::create('cards', function (Blueprint $table) {
            $table->increments('id');
            $table->unsignedInteger('user_id');
            $table->string('token');
            $table->string('last4');
            $table->timestamps();
            $table->softDeletes();
        });

I have a ‘belongs to’ relationship between a ‘recurring_payment’ and a ‘card’

class RecurringPayment extends Model
{
    protected $guarded = [];

    public function card()
    {
        return $this->belongsTo(Card::class, 'token');
    }
}

When I try to store the recurring payment

class Card extends Model
{
    use SoftDeletes;

    protected $fillable = [
        'user_id',
        'token',
        'last4',
    ];

    protected $hidden = [
        'user_id',
        'token',
        'created_at',
        'updated_at',
    ];
...

public function storeRecurringPayment($payment, $user)
    {
        $attributes = [
            'user_id' => $user,
            'card_id' => $payment->source['id'],
            'day' => Carbon::now()->day()->addMonths(1)->format('d'),
            'amount' => $payment->amount
        ];
// dd($attributes);
        return $this->recurringPayment()->create($attributes);
    }

    public function recurringPayment()
    {
        return $this->hasOne(RecurringPayment::class);
    }
...
}

it will not populate the ‘card_id’, it complains that the ‘card_id’ cannot be null, which is what I want, so far enough, but the ‘card_id’ is populated, this is the $attributes array died and dumped just before it's passed to the 'return $this->recurringPayment()->create($attributes);'

array:4 [▼
  "user_id" => 3
  "card_id" => "src_4zcdnrruvgxetpkgxocg6hhk5m"
  "day" => "30"
  "amount" => 10
]

I’m specifying in the ‘recurring_payment’ that I want to use ‘token’ as the foreign key not the default ‘card_id’ but I still get this error

SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'card_id' cannot be null (SQL: insert into 'recurring_payments' ('user_id', 'card_id', 'day', 'amount', 'updated_at', 'created_at') values (3, ?, 30, 10, 2019-07-11 13:53:08, 2019-07-11 13:53:08))

Can anyone see the mistake I've made?

  • Hello, you have set column `card_id` nullable. You can do it with migration, please read: https://stackoverflow.com/questions/24419999/laravel-migration-change-to-make-a-column-nullable – Kusy Jul 11 '19 at 14:02
  • Can you add the code from the `recurringPayment()` relationship to your question. – Remul Jul 11 '19 at 14:04
  • @Kusy yes I've set card_id to nullable and that lets it populate the table, but with a a null card_id, and the card_id needs to be populated so I can have the relation with the card.token field – Nicolas Thompson Jul 11 '19 at 14:06
  • just curious but why are you using token as the foreign key? – Brad Goldsmith Jul 11 '19 at 14:08
  • @Kusy yes the ```recurringPayment()``` relationship is in the class belongsTo(Card::class, 'token'); } } ``` – Nicolas Thompson Jul 11 '19 at 14:09
  • @BradGoldsmith because the token is the unique identifier for the card, in the `recurring_payments` table it is `card_id` and in the card table it is `token` – Nicolas Thompson Jul 11 '19 at 14:14
  • Don't add code in the comments, edit your question and add it there. From the code you posted you are not using the `card()` relationship defined in your `RecurringPayment` model, add the code from the `recurringPayment()` method to the question, I assume it is in the `Card` model. – Remul Jul 11 '19 at 14:15
  • @Remul I've updated my question to include the Card->storeRecurringPayment() method and the recurringPayment relationship – Nicolas Thompson Jul 11 '19 at 14:21
  • Make sure all fields in your migration are in the `protected $fillable = []` array for both models (if it's not there, add it). I believe the `->create()` method requires that. – Tim Lewis Jul 11 '19 at 14:24
  • @TimLewis the fields are all opened up with this line `protected $guarded = []; ` in the RecurringPayment model – Nicolas Thompson Jul 11 '19 at 14:31
  • Ah you're right. I thought guarded was for something else, but I see they are the reverse of each other. Interesting. Can't say I've seen an issue like this before then. – Tim Lewis Jul 11 '19 at 14:35
  • @TimLewis yes `protected $fillable = [ 'user_id', 'card_id', 'day', 'amount' ];` has the same effect as `protected $guarded = [];` but thanks anyway – Nicolas Thompson Jul 11 '19 at 14:38
  • Could you try: `return $this->hasOne(RecurringPayment::class, null, 'token');` – Remul Jul 11 '19 at 14:39
  • @Remul good idea but that didn't work, still the same error `SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'card_id' cannot be null (SQL: insert into `recurring_payments` (`user_id`, `card_id`, `day`, `amount`, `updated_at`, `created_at`) values (3, ?, 30, 10, 2019-07-11 15:19:00, 2019-07-11 15:19:00))` – Nicolas Thompson Jul 11 '19 at 15:20
  • Is your `Card` model that you are calling `storeRecurringPayment()` on already persisted to the database? If not that would be the problem. – Remul Jul 11 '19 at 15:48

0 Answers0