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

Redirect Bundle Laravel Package

braune-digital/redirect-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require braune-digital/redirect-bundle "~1.1"
    

    Register the bundle in config/bundles.php (Laravel) or AppKernel.php (Symfony):

    BrauneDigital\RedirectBundle\BrauneDigitalRedirectBundle::class,
    
  2. First Use Case: Redirect a legacy URL (/old-page) to a new one (/new-page) with a 301 (permanent) status code:

    $redirectManager = app('braune_digital.redirect.manager');
    $redirectManager->create('/old-page', '/new-page', 301);
    
  3. Verify Setup: Check the redirects table in your database (auto-created by Doctrine migrations). Ensure the Redirect entity exists.


Implementation Patterns

Core Workflows

  1. Creating Redirects Programmatically: Use the RedirectManager to persist redirects dynamically (e.g., during migrations or admin actions):

    $manager->create('/deprecated', '/new-endpoint', 302); // Temporary redirect (302)
    
  2. Middleware Integration: Add a middleware to check redirects before routing:

    // app/Http/Middleware/CheckRedirects.php
    public function handle($request, Closure $next) {
        $redirect = app('braune_digital.redirect.manager')->findByPath($request->path());
        if ($redirect) {
            return redirect()->to($redirect->getRedirectPath())->setStatusCode($redirect->getStatusCode());
        }
        return $next($request);
    }
    

    Register in app/Http/Kernel.php:

    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\CheckRedirects::class,
            // ...
        ],
    ];
    
  3. Bulk Redirects: Import redirects from a CSV/Excel file during deployment:

    $csv = new \League\Csv\Reader(...);
    foreach ($csv->getRecords() as $record) {
        $manager->create($record['old_path'], $record['new_path'], $record['status_code'] ?? 301);
    }
    
  4. Admin Panel: Expose CRUD operations via a Laravel Nova/Livewire admin panel:

    // Nova Resource
    public static $redirectManager;
    public function fields(Request $request) {
        return [
            new Textfield('old_path'),
            new Textfield('redirect_path'),
            new Select('status_code', [301 => 'Permanent', 302 => 'Temporary']),
            new Button('Create', function () {
                self::$redirectManager->create($this->old_path, $this->redirect_path, $this->status_code);
            }),
        ];
    }
    

Integration Tips

  1. Doctrine Events: Listen for prePersist/preUpdate to auto-generate slugs or validate paths:

    // src/Events/RedirectSubscriber.php
    public function onPrePersist(PrePersistEventArgs $args) {
        $redirect = $args->getEntity();
        if ($redirect instanceof Redirect) {
            $redirect->setOldPath(strtolower(trim($redirect->getOldPath(), '/')));
        }
    }
    
  2. API Endpoints: Expose redirects as JSON for frontend use:

    Route::get('/api/redirects', function () {
        return Redirect::all()->map(fn ($r) => [
            'old_path' => $r->getOldPath(),
            'new_path' => $r->getRedirectPath(),
            'status' => $r->getStatusCode(),
        ]);
    });
    
  3. Testing: Mock the RedirectManager in PHPUnit:

    $mockManager = Mockery::mock('BrauneDigital\RedirectBundle\Manager\RedirectManager');
    $mockManager->shouldReceive('findByPath')->andReturn($redirectEntity);
    $this->app->instance('braune_digital.redirect.manager', $mockManager);
    

Gotchas and Tips

Pitfalls

  1. Path Matching:

    • The bundle uses exact path matching by default. For dynamic routes (e.g., /blog/{slug}), use regex or prefix-based matching:
      // Custom repository method
      public function findByRegexPath($path) {
          return $this->createQueryBuilder('r')
              ->where("r.oldPath REGEXP :path")
              ->setParameter('path', $path)
              ->getOneOrNullResult();
      }
      
  2. Status Code Validation:

    • The bundle doesn’t validate statusCode by default. Ensure only HTTP-compliant codes (e.g., 301, 302, 307) are used:
      // Add validation in Redirect entity
      public function setStatusCode($code) {
          if (!in_array($code, [301, 302, 307, 308])) {
              throw new \InvalidArgumentException("Invalid status code: $code");
          }
          $this->statusCode = $code;
      }
      
  3. Database Schema:

    • The bundle assumes a default redirects table. If using a custom schema, override the Entity\Redirect class or configure Doctrine mappings:
      # config/packages/braune_digital_redirect.yaml
      braune_digital_redirect:
          entity: App\Entity\CustomRedirect
      
  4. Caching:

    • Redirect lookups can be slow for large datasets. Cache results in Redis:
      $cacheKey = "redirect:{$request->path()}";
      $redirect = cache()->remember($cacheKey, now()->addHours(1), function () use ($request) {
          return app('braune_digital.redirect.manager')->findByPath($request->path());
      });
      

Debugging

  1. Missing Redirects:

    • Verify the RedirectManager is bound in the container. Check for typos in the service ID (braune_digital.redirect.manager).
    • Ensure Doctrine’s EntityManager is properly configured to auto-generate the redirects table.
  2. Redirect Loops:

    • Add a check in middleware to prevent infinite loops:
      if ($request->headers->get('X-Redirect-Checked')) {
          return $next($request);
      }
      $request->headers->set('X-Redirect-Checked', 'true');
      
  3. Case Sensitivity:

    • URLs are case-sensitive in HTTP. Normalize paths to lowercase:
      $manager->create('/Old-Path', '/new-path', 301);
      // Query with lowercase:
      $manager->findByPath(strtolower($request->path()));
      

Extension Points

  1. Custom Logic: Extend the Redirect entity to add metadata (e.g., created_at, expires_at):

    /**
     * @ORM\Column(type="datetime")
     */
    private $expiresAt;
    
  2. Batch Processing: Add a command to bulk-create redirects from a database dump:

    // src/Console/Commands/ImportRedirects.php
    public function handle() {
        $oldRedirects = DB::table('legacy_redirects')->get();
        foreach ($oldRedirects as $redirect) {
            app('braune_digital.redirect.manager')->create(
                $redirect->old_url,
                $redirect->new_url,
                $redirect->status_code ?? 301
            );
        }
    }
    
  3. Soft Deletes: Implement soft deletes for redirects:

    // Redirect entity
    use Doctrine\ORM\Mapping as ORM;
    /**
     * @ORM\Column(type="boolean")
     */
    private $isDeleted = false;
    
    public function delete() {
        $this->isDeleted = true;
        $this->deletedAt = new \DateTime();
    }
    

    Update the repository to filter out soft-deleted records.

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.
besmartand-pro/php-quality-config
sentix/ai-chatbot
codifyo/ts-generator-bundle
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor