Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enum route binding for optional routes does not support nullable enum values, and instead always returns null for the param #46471

Closed
dannypritchard opened this issue Mar 14, 2023 · 1 comment

Comments

@dannypritchard
Copy link

  • Laravel Version: 10.x
  • PHP Version: 8.1.6
  • Database Driver & Version: N/A

Description:

Optional route params in urls such as /businesses/{businessCategory?} where BusinessCategory is an enum defined in the controller method as optional with a default of null (i.e. BusinessCategory $businessCategory = null) don't actually act as optional params as they should. They currently only support casting a default value to the route, e.g. BusinessCategory $businessCategory = BusinessCategory::MBA -- if you don't supply a default value and instead make this optional with = null, you do not get ANY route binding for the enum, which definitely doesn't seem to be intentional behaviour. It always resolves to null.

So what causes this? When ReflectionParameter->getType() is cast to string for an optional controller method param, it will return '?App\Enum\BusinessCategory', which cannot be infered as an enum via enum_exists() due to the preceeding '?' returned from the Reflection stringification, breaking this use case for a an actual optional enum route param.

To fix this, we can instead use ReflectionParameter->getType()?->getName() in a couple of places, and cast that to string instead, which will return the real enum in its namespace (or empty string if it was null, maintain existing behaviour).

I have a fix for this ready to go with updated tests for the ImplicitBackedEnumRouteBindingTest class

Steps To Reproduce:

Given an enum

<?php

namespace App\Enums;
enum BusinessCategory: string
{    
    case MBA = 'mba';
    case CIA = 'cia';
}

used as an optional route param

Route::get('/businesses/{businessCategory?}', [BusinessController::class, 'index']);

for a controller

<?php
namespace App\Http\Controllers;
use App\Enums\BusinessCategory;

class BusinessController extends Controller{
    public function index(BusinessCategory $businessCategory = null): void
    {
        dd($businessCategory);
    }
}

If you implement this normal optional routing pattern, where you would expect the nullable route param to resolve if supplied and to be null if not supplied, you instead get NO enum binding at all. $businessCategory is always null.

@morloderex
Copy link
Contributor

@DannyRevenant I have added a pr which should fix this problem :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants