0

I'm using the package hashids\hashids to hash the ID of data sent through the URL (e.g .../post/bsdfs/edit, the 'bsdfs' is the encoded value). I followed Stuart Wagner's accessor method to do so. Below is how I do it:

use Hashids\Hashids;

class Post extends Model {
    protected $appends = ['hashid'];

    public function getHashidAttribute() {
        $hashid = new Hashids(config('hash.keyword'));

        return $hashid->encode($this->attributes['id']);
    }
}

Before hashing the IDs I am getting post/2/edit. After the hashing process, I'm getting post/bsdfs/edit, which is fine to me.

The problem occurs when redirecting to the encoded route. This is how my route looks like:

use App\Http\Controllers\PostController;
    
Route::get('post/{post}/edit', 'PostController@edit')->name('post.edit');

After redirecting, I get a 404 error. This is what the controller accepts:

Use App\Models\Post;

class PostController extends Controller {
    //PS: I don't actually know what this method is called...
    public function edit(Post $post) {
        return view('post.edit')->with(compact('post'));
    }
}

I know that if I'm doing this method, Laravel is searching for an ID of 'bsdfs', which does not exist in the database. What it should do is decode the hash and get the ID. Is there a way to do it WITHOUT doing this:

public function edit($id) {
    $hashid = new Hashids(config('hash.keyword'));
    $id= $hashid->decode($id);

    $post = Post::find($id);

    return view('post.edit')->with(compact('post'));
}

As you can see, my goal here is to reduce the number of lines while still maintaining the data ID in the URL to be encoded. Any help would be appreciated. Thank you.

EricSchaefer
  • 25,272
  • 21
  • 67
  • 103

1 Answers1

2

You could take advantage of Model Binding.

So your model should have something like this:

/**
 * Retrieve the model for a bound value.
 *
 * @param  mixed  $value
 * @param  string|null  $field
 * @return \Illuminate\Database\Eloquent\Model|null
 */
public function resolveRouteBinding($value, $field = null)
{
    $hashid = new Hashids(config('hash.keyword'));

    return $this->findOrFail($hashid->decode($value)[0]);
}

So you can then have your controller like nothing happend:

public function edit(Post $post)
{
    return view('post.edit')->with(compact('post'));
}
matiaslauriti
  • 7,065
  • 4
  • 31
  • 43
  • The data returned is in the form of array. Is this because of hashids\hashids? – nazhannasir Apr 19 '21 at 04:00
  • What of all 3 possible points are return as array ? `$hashid->decode($value)`, ` return $this->findOrFail(...)` or ` return view('post.edit')->with(compact('post'));` ? Share here the error you are now having please... – matiaslauriti Apr 19 '21 at 04:02
  • I dd($hashid->decode($value));, it returns array : 1 [ [0] => 1 ].. I didnt receive an error, but the eloquent is empty – nazhannasir Apr 19 '21 at 04:04
  • I never used the library you are using, I saw the [documentation](https://github.com/vinkla/hashids) on github and I see that `decode()` will always return an array with 1 or more elements. So see my updated answer and try it. – matiaslauriti Apr 19 '21 at 04:25
  • I see, so it is the limitation of the library itself. Ok thanks alot for your help! I'll mark this as the right answer. – nazhannasir Apr 19 '21 at 04:29
  • Is it better to call an attribute that would return the hashed id, or save it to the database? – Adam Patterson Nov 14 '21 at 01:47