Ldaprecord-laravel: [Support] Route Model Binding and Pagination ala Laravel

Created on 22 Apr 2021  路  12Comments  路  Source: DirectoryTree/LdapRecord-Laravel

Hi @stevebauman, are that possible to add route model binding feature in Laravel to LDAPRecord and add pagination via Collection API that Laravel has?

So far, for handling pagination I convert LDAPRecord model to collection and install spatie/laravel-collection-macros to call paginate method.



question

All 12 comments

Hi @satyakresna! Another great question.

I believe you should be able to accomplish this by creating your own LdapRecord model and adding the getRouteKey() and resolveRouteBinding() method:

namespace App\Ldap;

use LdapRecord\Models\ActiveDirectory\User as BaseUser;

class User extends BaseUser
{
    public function getRouteKey()
    {
        return $this->getObjectGuid();
    }

    public function resolveRouteBinding($value, $field = null)
    {
        return $this->findByGuid($value);
    }
}

Then, in your Laravel controllers/routes, it should be resolved through type-hints when you supply the users Object GUID as a URL parameter:

use App\Ldap\User;

Route::get('/ldap/users/{user}', function (User $user) {
    // ...
});

Can you give that a shot?

Hi @stevebauman, I try and it looks like the another values like uid, givenname, cn, mail, etc don't appear when I run dd($user).

Here are my codes:

Web Route

<?php
Route::get('/users/{user}/edit', [UserController::class, 'edit'])->name('users.edit');

Controller

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Ldap\User;

class UserController extends Controller
{

    public function edit(User $user)
    {
        dd($user);
    }
}

Model

<?php

use LdapRecord\Models\OpenLDAP\User as BaseUser;

class User extends BaseUser
{

    public function getRouteKey()
    {
        return $this->getObjectGuid();
    }

    public function resolveRouteBinding($value, $field = null)
    {
        return $this->findByGuid($value);
    }

}

result-1

Hi @stevebauman, could you please follow up this issue?

Hi @satyakresna -- apologies. You're right -- the above doesn't work.

You will have to bind the models explicitly inside of the router using:

  • Route::model('parameter', Model::class) or;
  • Route::bind('parameter', Closure $callback) (if you want the model resolution logic outside of the model)

You can use either approach. Here's a quick overview of setting up both:

Using Route::model():

App\Providers\RouteServiceProvider.php:

// app/Providers/RouteServiceProvider.php

public function boot()
{
    // ...

    Route::model('ldap-user', \App\Ldap\User::class);
}

App\Ldap\User.php:

<?php
namespace App\Ldap;

use LdapRecord\Models\OpenLDAP\User as BaseUser;

class User extends BaseUser
{
    public function resolveRouteBinding($value)
    {
        return $this->findByGuid($value);
    }
}

routes/web.php:

Route::get('/ldap/users/{ldap-user}', [LdapUserController::class, 'index']);

Using Route::bind():

App\Providers\RouteServiceProvider.php:

// app/Providers/RouteServiceProvider.php

public function boot()
{
    // ...

    Route::bind('ldap-user', function ($value) {
        return \App\Ldap\User::findByGuid($value);
    });
}

routes/web.php:

Route::get('/ldap/users/{ldap-user}', [LdapUserController::class, 'index']);

Then, you should be able to visit the route with a string based GUID (or whichever attribute you use to locate an LDAP object) and it will resolve the model in your controller.

Let me know if you run into any issues! 馃憤

Hi @stevebauman, I try but it throws 404 Not Found. Here's my code. The url in browser looks like this: http://localhost:8002/users/[email protected],ou=users,dc=unud,dc=ac,dc=id/edit

Route

Route::get('/users/{ldap-user}/edit', [UserController::class, 'edit'])->name('users.edit');

Controller

<?php

namespace App\Http\Controllers;

use App\Ldap\User;

class UserController extends Controller
{

    public function edit(User $user)
    {
        dd($user);
    }
}

Model

<?php

namespace App\Ldap;

use LdapRecord\Models\OpenLDAP\User as BaseUser;
use LdapRecord\Query\Model\Builder;

class User extends BaseUser
{

     /**
     * The object classes of the LDAP model.
     *
     * @var array
     */
    public static $objectClasses = [
        'eduPerson',
        'inetOrgPerson',
        'organizationalPerson',
        'person',
        'top',
        'unudPerson',
    ];

    public function getRouteKey()
    {
        return $this->getObjectGuid();
    }

    public function resolveRouteBinding($value)
    {
        return $this->findByGuid($value);
    }
}

Hi @stevebauman, could you please follow up this issue? Thank you.

Hey @satyakresna,

I believe your URL is incorrect. You're supplying a full distinguished name, when only the entryuuid should be given, as this attribute is used as the ObjectGUID for OpenLDAP:

https://github.com/DirectoryTree/LdapRecord/blob/ed79f7fc18355fbfde305793cffcad39bd1deed6/src/Models/OpenLDAP/Entry.php#L11-L19

Feel free to override the above attribute ($guidKey) if you'd prefer to find users by a different unique identifier for your LDAP environment.

If instead you'd prefer to keep using full distinguished names in the URL, then you will instead have to use the find() method, instead of findByGuid():

<?php
namespace App\Ldap;

use LdapRecord\Models\OpenLDAP\User as BaseUser;

class User extends BaseUser
{
    public function resolveRouteBinding($dn)
    {
        return $this->find($dn);
    }
}

Note, that if you're going to be supplying full DN's inside of the URL, you will have to URLEncode them, because DN's contain comma (,) and equal (=) symbols, which are reserved in URLs for query parameters.

Hope this helps!

Hi @stevebauman, I would like use the entryuuid. But, somehow OpenLDAP throws dn instead of entryuuid. Here are the code and screenshots

Model

<?php

namespace App\Ldap;

use LdapRecord\Models\OpenLDAP\User as BaseUser;
use LdapRecord\Query\Model\Builder;

class User extends BaseUser
{

    public function getRouteKeyName()
    {
        return 'entryuuid';
    }

    public function resolveRouteBinding($value)
    {
        return $this->findBy('entryuuid', $value);
    }
}

Service Provider

// app/Providers/RouteServiceProvider.php

public function boot()
{
    // ...

    Route::model('ldap-user', \App\Ldap\User::class);
}

Web Route

Route::get('/users/{ldap-user}/edit', [UserController::class, 'edit'])->name('users.edit');

Blade

<a href="{{ route('users.edit', $user) }}"/></a>

Hover the link

Screenshot 2021-05-01 10 13 25

dd($user)

result-3

dd($users)

result-1

Could you please help about this issue?

Hi @stevebauman, could you please follow up this issue? Thanks.

Hi @satyakresna,

That's because you're passing in an LdapRecord model into blade, and the model is being resolved into a string.

When a model is resolved into a string, it will return the models distinguished name.

For example:

<a href="{{ route('users.show', $ldapUser) }}">View User</a>

Which executes:

<a href="<?php echo route('users.show', $ldapUser->__toString()); ?>">View User</a>

https://github.com/DirectoryTree/LdapRecord/blob/2d1c4d71dd900b2f8245a6e32f67274795fac8a2/src/Models/Model.php#L435-L443

Which then outputs:

<a href="/users/uid=john doe,dc=local,dc=com">View User</a>

You will instead pass the entryUUID manually:

<a href="{{ route('users.show', $ldapUser->getFirstAttribute('entryUUID')) }}">View User</a>

Hi @stevebauman, it works great right now. Thanks a lot for your help. I was confused why it doesn't work and the culprit is the declaration route binding method. Ha ha ha ha.

In the code you given is like this:

// app/Providers/RouteServiceProvider.php

public function boot()
{
    // ...

    Route::model('ldap-user', \App\Ldap\User::class);
}
Route::get('/users/{ldap-user}/edit', [UserController::class, 'edit'])->name('users.edit');

It must be:

// app/Providers/RouteServiceProvider.php

public function boot()
{
    // ...

    Route::model('user', \App\Ldap\User::class);
}
Route::get('/users/{user}/edit', [UserController::class, 'edit'])->name('users.edit');

No problem! Happy to help. Really glad you've worked it out 馃帀

Was this page helpful?
0 / 5 - 0 ratings

Related issues

AlexH269 picture AlexH269  路  4Comments

jagDanJu picture jagDanJu  路  8Comments

siegherr picture siegherr  路  6Comments

brinkonaut picture brinkonaut  路  6Comments

stephancasas picture stephancasas  路  6Comments