Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

mgarciadelojo's avatar

Tests does not work when overriding a helper

Hi everybody!

I am starting to do my first tests in a website I am working on, and I would need some support from you guys! I've been struggling with prefixes and routing to implement a multilanguage site. My solution was:

  1. Create a middleware called Multilanguage.php in app/Http/Middleware:
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Foundation\Application;
use Illuminate\Http\Request;
use Illuminate\Routing\Redirector;

class Multilanguage
{
    /**
     * Multilanguage constructor.
     *
     * @param Application $app
     * @param Redirector  $redirector
     * @param Request     $request
     */
    public function __construct(Application $app, Redirector $redirector, Request $request) {
        $this->app = $app;
        $this->redirector = $redirector;
        $this->request = $request;
    }

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @param  string|null  $guard
     * @return mixed
     */
    public function handle($request, Closure $next, $guard = null)
    {
        // Make sure current locale exists.
        $locale = $request->segment(1);

        if (in_array($locale, $this->app->config->get('app.skip_locales'))) {
            return $next($request);
        }

        if ( ! array_key_exists($locale, $this->app->config->get('app.locales'))) {
            $segments = $request->segments();
            $segments[0] = $this->app->config->get('app.fallback_locale');

            $newUrl = implode('/', $segments);
            if (!empty($_SERVER['QUERY_STRING'])) {
                $newUrl .= '?' . $_SERVER['QUERY_STRING'];
            }

            return $this->redirector->to($newUrl);
        }

        $this->app->setLocale($locale);

        return $next($request);
    }
}
  1. Add the middleware in Kernel.php file:
    protected $middleware = [
        \App\Http\Middleware\Multilanguage::class,
        \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
    ];
  1. Edit the RouteServiceProvider.php in the folder app/Providers:
<?php

namespace App\Providers;

use Illuminate\Http\Request;
use Illuminate\Routing\Router;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;

class RouteServiceProvider extends ServiceProvider
{
    /**
     * This namespace is applied to the controller routes in your routes file.
     *
     * In addition, it is set as the URL generator's root namespace.
     *
     * @var string
     */
    protected $namespace = 'App\Http\Controllers';

    /**
     * Define your route model bindings, pattern filters, etc.
     *
     * @param  \Illuminate\Routing\Router  $router
     * @return void
     */
    public function boot(Router $router)
    {
        //

        parent::boot($router);
    }

    /**
     * Define the routes for the application.
     *
     * @param  \Illuminate\Routing\Router  $router
     * @return void
     */
    public function map(Router $router, Request $request)
    {
        $locale = $request->segment(1);
        $this->app->setLocale($locale);

        $router->group(['namespace' => $this->namespace, 'prefix' => '{lang}'], function ($router) {
            require app_path('Http/routes.php');
        });
    }
}
  1. Then, I created a file called helpers.php in app/Http with this content:
<?php

if (!function_exists('route')) {
    /**
     * Generate a URL to a named route.
     *
     * @param  string                    $name
     * @param  array                     $parameters
     * @param  bool                      $absolute
     * @param  \Illuminate\Routing\Route $route
     * @return string
     */
    function route($name, $parameters = [], $absolute = true, $route = null)
    {
        if ( ! isset($parameters['lang'])) {
            $parameters['lang'] = App::getLocale();
        }

        return app('url')->route($name, $parameters, $absolute, $route);
    }
}
  1. Then, I edited the file bootstrap/autoload.php, and added this line at the beginning:
require __DIR__.'/../app/Http/helpers.php';

This way, I can use route helper in my templates when I don't specify the current lang parameter all the time.

The thing is my site is working fine, but when I run phpunit with the default laravel's tests, it throws the message..

Caused by
Illuminate\Routing\Exceptions\UrlGenerationException: Missing required parameters for [Route: team.index] [URI: {lang}/team]. in /home/vagrant/vacationdays/vendor/laravel/framework/src/Illuminate/Routing/Exceptions/UrlGenerationException.php:17

I suspect that phpunit is not loading the autoloader the same way that laravel does. Do you have any idea?

Thank you very much!!

0 likes
5 replies
bobbybouwmann's avatar

You can add the file to your composer file, so it's auto loaded in PHPUnit as well

"autoload": {
    "files": [
        "app/Http/helpers.php"
    ],
    "classmap": [
        "database"
    ],
    "psr-4": {
        "App\\": "app/"
    }
},
mgarciadelojo's avatar

Hi @bobbybouwmann!

Thank you for your quick response! I already tried that with no luck...

If I remove the function_existsin the app/Http/helpers.php file, then I get this error:

PHP Fatal error:  Cannot redeclare route() (previously declared in /home/vagrant/ZZZ/vendor/laravel/framework/src/Illuminate/Foundation/helpers.php:572) in /home/vagrant/ZZZ/app/Http/helpers.php on line 19

Now, I ask myself if PHPUnit is really loading the composer.json file...

aarinsmith's avatar
Level 1

Hi @mgarciadelojo

The problem is the order in which phpunit bootstraps the app. Although it looks to be doing the correct thing it creates problems because it seems that the even though the require for your custom function in the bootstrap autoload comes first it declares the internal route function first and ignores your custom implementation. Although this works as it should when you run the app it causes problems in testing it.

I was having the same issue and the solution I came up with is to just rename the custom route function. Use something like ml_route for multi-language route and use this instead wherever route is needed. It may not be ideal but it prevents naming conflicts and ensures your custom function will always be defined at run time.

mgarciadelojo's avatar

Hi @aarinsmith,

Many thanks for your reply.

I was looking for a method that doesn't affect front devs, so they didn't have to modify anything in the views, but at the end I discarded unit testing in this project because of this issue... Anyway, I'll think about it other future projects :)

Cheers,

Please or to participate in this conversation.