Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Ldaprecord Laravel Package

directorytree/ldaprecord

LDAPRecord is an LDAP directory and Active Directory ORM for Laravel and PHP. It provides fluent models, query builder, authentication and user sync, event-driven operations, and easy integration with Laravel apps for managing and searching directory entries.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require directorytree/ldaprecord
    

    Publish the config:

    php artisan vendor:publish --provider="DirectoryTree\LdapRecord\Laravel\LdapRecordServiceProvider" --tag="ldaprecord.config"
    
  2. Configure LDAP Connection (config/ldap.php):

    'connections' => [
        'ad' => [
            'host' => 'ldap.example.com',
            'port' => 389,
            'use_ssl' => true,
            'base_dn' => 'dc=example,dc=com',
            'username' => 'cn=admin,dc=example,dc=com',
            'password' => 'password',
            'timeout' => 5,
        ],
    ],
    
  3. Define a Model (app/Models/Ldap/User.php):

    use DirectoryTree\LdapRecord\Laravel\Model;
    
    class User extends Model
    {
        protected $connection = 'ad';
        protected $dn = 'cn=*,ou=users,dc=example,dc=com';
        protected $attributes = [
            'cn', 'sn', 'givenName', 'mail', 'userPrincipalName'
        ];
        protected $casts = [
            'mail' => 'string',
            'userPrincipalName' => 'string',
        ];
    }
    
  4. First Query:

    use App\Models\Ldap\User;
    
    $users = User::where('mail', '*@example.com')->get();
    

First Use Case: Authentication

use DirectoryTree\LdapRecord\Laravel\Auth\AuthenticatesUsers;

class LdapAuthController extends Controller
{
    use AuthenticatesUsers;

    public function login(Request $request)
    {
        $credentials = $request->only('username', 'password');
        if ($this->attemptLdapLogin($credentials)) {
            return redirect()->intended('/dashboard');
        }
        return back()->withErrors(['email' => 'Invalid credentials']);
    }
}

Implementation Patterns

Eloquent-Like Querying

Leverage familiar Laravel syntax for LDAP operations:

// Basic search
User::where('mail', 'john@example.com')->first();

// Nested conditions
User::where('department', 'IT')
    ->where(function ($query) {
        $query->where('role', 'admin')
              ->orWhere('role', 'manager');
    })
    ->get();

// Pagination
User::paginate(10);

// Chunking (for large datasets)
User::chunk(100, function ($users) {
    foreach ($users as $user) {
        // Process user
    }
});

Global Scopes for Tenant/Role Filtering

use DirectoryTree\LdapRecord\Laravel\Scope;

class TenantScope implements Scope
{
    public function apply(Builder $builder, Model $model)
    {
        $tenantId = auth()->id();
        $builder->where('ou', "ou=tenant_{$tenantId},dc=example,dc=com");
    }
}

class User extends Model
{
    protected static function booted()
    {
        static::addGlobalScope(new TenantScope);
    }
}

Authentication Workflows

// Attempt login
if (Auth::attemptLdap(['username' => 'john', 'password' => 'secret'])) {
    // Success
}

// Password updates
$user = User::find('john@example.com');
$user->password = 'newpassword';
$user->save();

// Bind directly
$ldap = app('ldap');
$bind = $ldap->bind('cn=admin,dc=example,dc=com', 'password');

Model Relationships

class Group extends Model
{
    public function members()
    {
        return $this->hasMany(User::class, 'memberOf', 'dn');
    }
}

class User extends Model
{
    public function groups()
    {
        return $this->belongsToMany(Group::class, 'memberOf', 'dn', 'member');
    }
}

Connection Management

// Switch connections dynamically
User::onConnection('backup_ad')->get();

// Configure multiple connections
'connections' => [
    'ad' => [...],
    'backup_ad' => [
        'host' => 'backup.ldap.example.com',
        // ...
    ],
],

Testing with DirectoryFake

use DirectoryTree\LdapRecord\Testing\DirectoryFake;

beforeEach(function () {
    DirectoryFake::new()
        ->withDirectory('dc=example,dc=com')
        ->withEntry('cn=john,ou=users,dc=example,dc=com', [
            'cn' => 'John Doe',
            'mail' => 'john@example.com',
        ]);
});

it('finds a user', function () {
    $user = User::where('mail', 'john@example.com')->first();
    expect($user->cn)->toBe('John Doe');
});

Gotchas and Tips

Pitfalls

  1. Global Scope Mutations:

    • Issue: Global scopes may unintentionally modify queries in unexpected ways (fixed in v4.0.6).
    • Fix: Test nested conditions with where() and orWhere() in global scopes. Use withoutGlobalScopes() for debugging:
      User::withoutGlobalScopes()->where('mail', '*')->get();
      
  2. 32-bit PHP Timestamp Issues:

    • Issue: Date attributes may produce invalid UNIX timestamps on 32-bit PHP (fixed in v4.0.4).
    • Fix: Ensure your server uses 64-bit PHP. For legacy systems, cast dates manually:
      protected $casts = [
          'lastLoginTime' => 'datetime:Y-m-d H:i:s',
      ];
      
  3. Empty whereIn Queries:

    • Issue: whereIn() with an empty array returns all results instead of none (fixed in v3.8.5).
    • Fix: Validate input arrays:
      if (!empty($ids)) {
          User::whereIn('id', $ids)->get();
      }
      
  4. TLS/SSL Errors:

    • Issue: ldap_start_tls() may fail with "Local error" (fixed in v3.6.0).
    • Fix: Ensure use_ssl is set to false and start_tls is explicitly enabled:
      'connections' => [
          'ad' => [
              'use_ssl' => false,
              'start_tls' => true,
              // ...
          ],
      ],
      
  5. Boolean Casts:

    • Issue: Reverse boolean casts may fail with LDAP string booleans (fixed in v3.6.3).
    • Fix: Explicitly define casts:
      protected $casts = [
          'accountDisabled' => 'boolean',
      ];
      
  6. Base DN Substitution:

    • Issue: {base} in whereMemberOf may not work (fixed in v3.8.2).
    • Fix: Use fully qualified DNs or test substitution:
      Group::whereMemberOf('CN=IT,OU=Groups,{base}')->get();
      

Debugging Tips

  1. Enable Debugging:

    // config/ldap.php
    'debug' => env('LDAP_DEBUG', false),
    

    Use constants like Ldap::DEBUG_FILTER for granular logging.

  2. Query Logging:

    User::where('mail', '*')->toLdap()->get();
    // Outputs the raw LDAP filter for debugging.
    
  3. Connection Issues:

    • Verify credentials and permissions.
    • Test connectivity with:
      $ldap = app('ldap');
      $ldap->connect();
      
  4. Attribute Casting:

    • Use getAttribute() and setAttribute() for custom logic:
      public function getFullNameAttribute()
      {
          return "{$this->givenName} {$this->sn}";
      }
      
  5. Performance:

    • Avoid select('*') for large datasets. Explicitly define attributes:
      protected $attributes = ['cn', 'mail']; // Only fetch these
      
    • Use limit() and offset() for pagination:
      User::limit(10)->offset(20)->get();
      

Extension Points

  1. Custom Query Types: Extend the query builder for specialized operations:

    use DirectoryTree\LdapRecord\Query\Builder;
    
    class CustomBuilder extends Builder
    {
        public function listMembers()
        {
            return $this->queryType(self::QUERY_LIST)->get();
        }
    }
    
  2. Attribute Casting: Override casting logic for non-standard attributes:

    protected $casts = [
        'binaryGuid' => 'binaryGuid',
        'whenChanged' => '
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
ecotone/kafka
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata