skip to Main Content

I have a GET endpoint that accepts a boolean active and an integer ID as a query parameter. Something like GET /stuff?active=1&ID=10.

Neither of these parameters are required.

If I were to do GET /stuff?active=1 and would try to retrieve the value from the Request by doing $request->get('active') I would get a value of 1 as a string.

If having declare(strict_types=1) enabled and a method in a service such as

public function getBy(bool $active = null) {
   ...
}

And calling the method in a Controller for example

 $controllerMethod->getBy($request->get('active'))

would result in Argument #0 ($active) must be of type ?bool, string given which is obviously not good.

Now my question: Is there a way to cast the request parameters prior to them reaching the Controller? Perhaps in a FormRequest class somehow?

I’m well aware I can do $request->has('active') ? $request->get('active') : null in the Controller but this is just extra clutter that I would like to move somewhere else.

5

Answers


  1. 1 way (getter)

    <?php
    
    declare(strict_types=1);
    
    /**
     * @property-read ?string $active
     */
    class MyRequest extends IlluminateFoundationHttpFormRequest
    {
        public function rules(): array
        {
            // TODO: implement it
        }
    
        public function getActive(): bool 
        {
            return (bool)$this->query('active');
        }
    }
    
    // $controllerMethod->getBy($request->getActive());
    

    2 way (override)

    <?php
    
    declare(strict_types=1);
    
    /**
     * @property-read bool $active
     */
    class MyRequest extends IlluminateFoundationHttpFormRequest
    {
        public function rules(): array
        {
            // TODO: implement it
        }
    
        /**
         * @inheritDoc
         */
        protected function prepareForValidation(): void
        {
            $this->merge([
                'active' => (bool)$this->query('active'),
            ]);
        }
    }
    
    // $controllerMethod->getBy($request->active);
    
    Login or Signup to reply.
  2. Use mergeIfMissing.

    You can create your own custom middleware and put the below inside it or call the below inside the Controller’s constructor(depending upon your design)

    $request->mergeIfMissing(['active' => null /* or false */, 'ID' => -1]);
    
    Login or Signup to reply.
  3. Well, we all agree that query params are string!

    What you can do:

    
    getBy(Request $request){
    
       $request->boolean('active') // method returns true for 1, "1", true, "true", "on", and "yes". All other values will return false
    
    }
    
    Login or Signup to reply.
  4. you can create a middleware for this and try overwriting the parameter:

    <?php
    
    namespace AppHttpMiddleware;
    
    use Closure;
    use IlluminateHttpRequest;
    use SymfonyComponentHttpFoundationResponse;
    
    class CastAtiveToBool
    {
        public function handle(Request $request, Closure $next): Response
        {
    
            $is_active = null;
            if ($request->get('active') === 1) {
                $is_active = true;
            } elseif ($request->get('active') === 0) {
                $is_active = false;
            }
    
            $request->merge(['active' => $is_active]);
    
            return $next($request);
        }
    }
    
    Login or Signup to reply.
  5. Outsourcing that to a FormRequest class should be working with either:

    /**
     * Handle a passed validation attempt.
     */
    protected function passedValidation(): void
    {
        $this->replace(['active' => (bool)$this->active]);
    }
    

    or by doing the same even before validation inside:

    protected function prepareForValidation(): void
    

    Documentation

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search