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

Reserved Names Bundle Laravel Package

alister/reserved-names-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install via Composer:

    composer require alister/reserved-names-bundle
    

    (Note: Due to Symfony 4/5 compatibility, ensure your project meets the ^4.4 || ^5.0 requirement.)

  2. Register the Bundle: Add to config/bundles.php (Symfony 4+):

    return [
        // ...
        Alister\ReservedNamesBundle\AlisterReservedNamesBundle::class => ['all' => true],
    ];
    
  3. Configure Reserved Names: Define reserved names in config/packages/alister_reserved_names.yaml:

    alister_reserved_names:
        names:
            - admin
            - root
            - private
            - test
    
  4. First Use Case: Check a username in a controller or service:

    use Symfony\Component\HttpFoundation\Request;
    
    public function register(Request $request)
    {
        $username = $request->request->get('username');
        $reservedChecker = $this->get('alister_reserved_names.check');
    
        if ($reservedChecker->isReserved($username)) {
            throw new \RuntimeException('Username is reserved.');
        }
        // Proceed with registration...
    }
    

Implementation Patterns

Core Workflows

  1. Username Validation Pipeline: Integrate into registration/login flows:

    $cleaner = $this->get('alister_reserved_names.cleanusername');
    $cleaned = $cleaner->clean($username); // "user_123" → "user"
    $reservedChecker = $this->get('alister_reserved_names.check');
    
    if ($reservedChecker->isReserved($username) || $reservedChecker->isReserved($cleaned)) {
        // Reject username
    }
    
  2. Dynamic Reserved Names: Override defaults via environment variables or config:

    # config/packages/alister_reserved_names.yaml
    alister_reserved_names:
        names:
            - "%env(reserved_names_list)%"  # e.g., "admin,root,private"
    
  3. Service Integration: Use in form validators or DTOs:

    public function validateUsername(string $username): void
    {
        $cleaner = $this->container->get('alister_reserved_names.cleanusername');
        $checker = $this->container->get('alister_reserved_names.check');
    
        if ($checker->isReserved($cleaner->clean($username))) {
            throw new \InvalidArgumentException('Reserved username.');
        }
    }
    
  4. Event-Driven Checks: Attach to KernelEvents::REQUEST or custom events:

    $eventDispatcher->addListener(KernelEvents::REQUEST, function (RequestEvent $event) {
        $request = $event->getRequest();
        if ($request->isMethod('POST') && $request->request->has('username')) {
            $checker = $this->container->get('alister_reserved_names.check');
            if ($checker->isReserved($request->request->get('username'))) {
                $event->setResponse(new Response('Reserved username.', 400));
            }
        }
    });
    

Advanced Patterns

  1. Custom Reserved Name Providers: Extend functionality by creating a custom provider:

    use Alister\ReservedNamesBundle\Services\ReservedNamesInterface;
    
    class CustomReservedNames implements ReservedNamesInterface
    {
        public function isReserved(string $name): bool
        {
            $reserved = ['admin', 'custom_reserved'];
            return in_array(strtolower($name), $reserved);
        }
    }
    

    Register as a service:

    services:
        alister_reserved_names.check:
            class: App\Services\CustomReservedNames
    
  2. Local Overrides: Merge local reserved names with bundle defaults:

    alister_reserved_names:
        names:
            - "%kernel.project_dir%/config/reserved_names.yml"  # Load from file
    
  3. Testing Integration: Mock the service in unit tests:

    $mockChecker = $this->createMock(ReservedNamesInterface::class);
    $mockChecker->method('isReserved')->willReturn(true);
    
    $this->container->set('alister_reserved_names.check', $mockChecker);
    

Gotchas and Tips

Pitfalls

  1. Case Sensitivity: The bundle lowers all names before comparison. Ensure reserved names are lowercase in config to avoid false negatives.

  2. Noise Character Handling: The cleanusername service aggressively strips trailing s, digits, -, and _. Test edge cases like:

    • "admin123""admin" (flagged as reserved)
    • "admins""admin" (flagged)
    • "admin_""admin" (flagged)
  3. Symfony 4+ Compatibility:

    • The bundle requires Symfony 4.1.4+ (despite ^4.4 in composer.json).
    • If using Symfony 5, ensure config/bundles.php is used instead of AppKernel.php.
  4. Performance: The isReserved() method uses in_array(), which is O(n). For large reserved lists (>1000 names), consider:

    // Pre-compile reserved names into a hash set (e.g., SplFixedArray)
    $reservedNames = new \SplFixedArray(count($this->names));
    foreach ($this->names as $index => $name) {
        $reservedNames[$index] = strtolower($name);
    }
    
  5. Archived Status: The package is archived (no updates since 2018). Fork or extend if critical for your project.


Debugging Tips

  1. Verify Configuration: Dump the loaded reserved names to debug:

    $checker = $this->container->get('alister_reserved_names.check');
    var_dump($checker->getReservedNames()); // Check loaded list
    
  2. Cleaning Behavior: Log cleaned usernames to understand transformations:

    $cleaner = $this->container->get('alister_reserved_names.cleanusername');
    $original = 'Admin_123!';
    $cleaned = $cleaner->clean($original);
    \Log::debug("Original: {$original}, Cleaned: {$cleaned}");
    
  3. Override Services: Temporarily replace services for debugging:

    services:
        alister_reserved_names.check:
            class: Alister\ReservedNamesBundle\Services\ReservedNames
            arguments:
                $reservedNames: ['debug', 'test'] # Override for testing
    

Extension Points

  1. Custom Cleaning Logic: Extend CleanUserNames to handle domain-specific noise:

    class CustomCleaner extends \Alister\ReservedNamesBundle\Services\CleanUserNames
    {
        protected function getNoiseCharacters(): string
        {
            return parent::getNoiseCharacters() . '.@'; // Add custom chars
        }
    }
    

    Register as a service:

    services:
        alister_reserved_names.cleanusername:
            class: App\Services\CustomCleaner
    
  2. Validator Integration: Create a Symfony validator constraint (as suggested in the TODO):

    use Symfony\Component\Validator\Constraint;
    
    class ReservedUsername extends Constraint
    {
        public $message = 'This username is reserved.';
        public function validatedBy(): string { return static::class; }
    }
    
    class ReservedUsernameValidator extends ConstraintValidator
    {
        public function validate($value, Constraint $constraint)
        {
            $checker = $this->container->get('alister_reserved_names.check');
            if ($checker->isReserved($value)) {
                $this->context->buildViolation($constraint->message)
                    ->addViolation();
            }
        }
    }
    

    Use in entities:

    use App\Validator\Constraints\ReservedUsername;
    
    class User
    {
        #[ReservedUsername]
        private string $username;
    }
    
  3. Database-Backed Reserved Names: Fetch reserved names dynamically from a DB:

    class DatabaseReservedNames implements ReservedNamesInterface
    {
        public function isReserved(string $name): bool
        {
            return $this->entityManager->getRepository(ReservedName::class)
                ->exists(['lower(name) = ?1'], [strtolower($name)]);
        }
    }
    
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.
emuniq/filament-browser-notifications
syriable/filament-translator
hungnm28/livewire-form
wenprise/eloquent
crudly/encrypted
fadion/bouncy
cuci/prototurk-sdk
gos/pubsub-router-bundle
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle
codeflextech/permission-manager
karnoweb/livewire-datepicker
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui