I added hashes to my ID's using a trait. However by doing that now I can no longer use attach() or relationships.
For example this relationship does not work in my view anymore:
@foreach ($invoice->items as $item)
{{ $item->item }}
@endforeach
Here is the trait that hashes the id for me
<?php
namespace App\Traits;
use Hashids\Hashids;
use Illuminate\Database\Eloquent\Builder;
trait HashedId
{
/**
* Get the user's id as hashids.
*
* @param $value
* @return string
*/
public function getIdAttribute($value)
{
$hashids = new \Hashids\Hashids(env('APP_KEY'),10);
return $hashids->encode($value);
}
public function scopeHashId(Builder $query, $id)
{
$hashIds = new Hashids(env('APP_KEY'), 10);
$id = $hashIds->decode($id)[0];
return $query->where('id', $id);
}
}
Invoice Model:
<?php
namespace App;
use App\Traits\HashedId;
use Illuminate\Database\Eloquent\Model;
use HipsterJazzbo\Landlord\BelongsToTenants;
class Invoice extends Model
{
use BelongsToTenants;
use HashedId;
//
protected $fillable = [
'client_id',
'invoice_number',
'purchase_order',
'invoice_note',
'invoice_status',
'invoice_total',
'invoice_type',
'sub_total',
'balance_due',
'due_date',
'invoice_type',
'user_id',
];
protected $hidden = [
'user_id'
];
public function items()
{
return $this->belongsToMany('App\LineItem', 'invoice_items', 'invoice_id', 'item_id');
}
public function client()
{
return $this->belongsTo('App\Client');
}
}
I have tried doing this from a controller but it feels more like a hack than the right way to do it and I still lose the ability to use things like $invoice->attach($lineItem)
or $invoice->items
//Currently I have to unhash the ids in order to save them as a pivot
$hashIds = new \Hashids\Hashids(env('APP_KEY'), 10);
$invoiceId = $hashIds->decode($request->invoice_id)[0];
$lineItemId = $hashIds->decode($request->item_id)[0];
//Should have been able to use $invoice->attach($lineItemId)
DB::table('invoice_items')->insert(
['invoice_id' => $invoiceId, 'item_id' => $lineItemId]
);
How can I continue to use $invoice->attach($lineItem)
or $invoice->items
from controllers while still using the trait that hashes my ids?
I've re-written the trait as follows (this assumes you're using PHP 5.6 or above):
<?php
namespace App\Traits;
use Hashids\Hashids;
use Illuminate\Database\Eloquent\Builder;
trait HashedId
{
/**
* Get model ID attribute encoded to hash ID.
*
* @return string
*/
public function getHashIdAttribute()
{
$hashIds = new Hashids(env('APP_KEY'), 10);
return $hashIds->encode($this->getKey());
}
/**
* Restrict query scope to find model by encoded hash ID.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param integer $id
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeHashId(Builder $query, $id)
{
$hashIds = new Hashids(env('APP_KEY'), 10);
$id = $hashIds->decode($id)[0];
return $query->where('id', $id);
}
/**
* Restrict query scope to find models by encoded hash IDs.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param array $ids
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeHashIds(Builder $query, ...$ids)
{
$hashIds = new Hashids(env('APP_KEY'), 10);
$ids = array_map(function ($id) use ($hashIds) {
return $hashIds->decode($id)[0];
}, $ids);
return $query->whereIn('id', $ids);
}
}
You may notice that I've renamed the accessor, getIdAttribute()
to getHashIdAttribute()
. You can therefore now get the hash ID of a model instance by calling $model->hash_id
instead of $model->id
.
This is where I think your problem was, because Laravel was expecting an integer key to be returned by $model->id
, whereas it would have been getting the hash ID instead.
If after implementing the changes above you're still getting an error, can you show what the specific error is?