regan
regan

Reputation: 405

Laravel with 2 Primary Keys - update "increment" method?

I am using this solution for 2 primary keys in Laravel: https://stackoverflow.com/a/37076437/225114

Can anyone tell me how to also override the Eloquent "increment" method to work with duplicate keys?

Laravel Framework 5.8.35

I am including the 'CompositePrimaryKey ' trait into models like...

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use App\Models\Traits\CompositePrimaryKey;

class Devices extends Model
{
    public $table = 'devices';
    protected $primaryKey = ['id1','id2'];
    public $incrementing = false;
    public $timestamps = false;

    use CompositePrimaryKey;

}

And here is the trait:

namespace App\Models\Traits;

use Illuminate\Database\Eloquent\Builder;

trait CompositePrimaryKey {
    /**
     * Set the keys for a save update query.
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    protected function setKeysForSaveQuery(Builder $query)
    {
        $keys = $this->getKeyName();
        if(!is_array($keys)){
            return parent::setKeysForSaveQuery($query);
        }

        foreach($keys as $keyName){
            $query->where($keyName, '=', $this->getKeyForSaveQuery($keyName));
        }

        return $query;
    }
    /**
     * Get the primary key value for a save query.
     *
     * @param mixed $keyName
     * @return mixed
     */
    protected function getKeyForSaveQuery($keyName = null)
    {
        if(is_null($keyName)){
            $keyName = $this->getKeyName();
        }

        if (isset($this->original[$keyName])) {
            return $this->original[$keyName];
        }

        return $this->getAttribute($keyName);
    }
    /**
   * Perform the actual delete query on this model instance.
   *
   * @return void
   */
  protected function runSoftDelete()
  {
    $query = $this->newQueryWithoutScopes()->where($this->getKeyName()[0], $this->attributes[$this->getKeyName()[0]])
    ->where($this->getKeyName()[1], $this->attributes[$this->getKeyName()[1]]);
    $time = $this->freshTimestamp();
    $columns = [$this->getDeletedAtColumn() => $this->fromDateTime($time)];
    $this->{$this->getDeletedAtColumn()} = $time;
    if ($this->timestamps && ! is_null($this->getUpdatedAtColumn())) {
      $this->{$this->getUpdatedAtColumn()} = $time;

      $columns[$this->getUpdatedAtColumn()] = $this->fromDateTime($time);
    }
    $query->update($columns);
  }

}

Thanks.

Upvotes: 1

Views: 593

Answers (1)

konstantinkoslow
konstantinkoslow

Reputation: 287

The very first thing you need to do is to look at your table structure and check for your primary keys. These must be declared as primary and may not increment.

If you are using laravel migrations for your model it should look like this:

public function up()
{
    Schema::create('devices', function (Blueprint $table) {
        $table->bigInteger('id1');
        $table->string('id2');

        ...

        $table->primary(['id1', 'id2']);
    });
}

If this one's clean, just add the following function at the beginning of your trait:

...
use Illuminate\Database\Eloquent\Builder;

trait CompositePrimaryKey
{
    public function getIncrementing()
    {
        return false;
    }

And set your trait at the beginning of your model, not at the end. That's it.

...
class Devices extends Model
{

    use CompositePrimaryKey;

    ...

Finally, you can remove the declaration of the variable in your model public $incrementing = false;, because it is redundant now.

Upvotes: 1

Related Questions