Api: using Helpers trait and controller constructor [max nesting level error]

Created on 25 May 2016  路  5Comments  路  Source: dingo/api

This code will give this error: (all routes of this controller are api protected)

"Maximum function nesting level of '200' reached, aborting!"

class UserController {
   use Helpers;

   public function __construct()
   {
      $this->user = $this->user(); // WHY? No problem if we use "this->user()" without injecting in the constructor
   }

   public function me()
   {
      return $this->item($this->user, UserTransformer::class);
   }

   public function update(Request $request)
   {
      $this->user->update($request->all());

      return $this->item($this->user, UserTransformer::class);
   }
}

Why is this? I'm using last versions of laravel and dingo

Most helpful comment

You have an infinite loop there.

You cant use $this->user() on __construct method because it will be recursive. This errors occurs only if the user variable isn't set and if the user isn't authenticated.

Keep in mind that at this point the route object doesn't exist yet. So the API try to authenticate the user (https://github.com/dingo/api/blob/master/src/Auth/Auth.php#L151) that will try to use each provider available (https://github.com/dingo/api/blob/master/src/Auth/Auth.php#L82) to do so. This authenticate function expects as parameter 2 the current route (that doesn't exist remember?).

So the function $this->router->getCurrentRoute() called as parameter 2 take us to Router.php calling $this->createRoute($route) (https://github.com/dingo/api/blob/master/src/Routing/Router.php#L691) that creates a new Route object (https://github.com/dingo/api/blob/master/src/Routing/Router.php#L713).

In this point tracking the Route object and its construct method it calls $this->setupRouteProperties($request, $route) (https://github.com/dingo/api/blob/master/src/Routing/Route.php#L144) that calls $this->mergeControllerProperties() (https://github.com/dingo/api/blob/master/src/Routing/Route.php#L167) that finally calls $this->makeControllerInstance() (https://github.com/dingo/api/blob/master/src/Routing/Route.php#L186).

So makeControllerInstance method is making a new instance of our controller (https://github.com/dingo/api/blob/master/src/Routing/Route.php#L325) that's call our __construct method again, that fires $this->user() again, and the stack begins again.

This will be recursive until the max stack on nesting level in xDebug be reached that for you is 200 (but for me is 256). BTW you can deactivate xDebug or set the maximum nesting level in the php.ini higher using xdebug.max_nesting_level=500 for example.

So this proves that you can't use $this->user() on __construct method.

But the real question is WHY you need to use that or even set it to a user property when the Helpers trait dynamic offers you that user property by magic method __get as an alias for user() method?

All 5 comments

Are you sure it was supposted to work with class string. In the wiki you will find like this

return $this->response->item($user, new UserTransformer);

@catalinux Yes, but it doesn't matter, is an example code, the problem is in the constructor.

You have an infinite loop there.

You cant use $this->user() on __construct method because it will be recursive. This errors occurs only if the user variable isn't set and if the user isn't authenticated.

Keep in mind that at this point the route object doesn't exist yet. So the API try to authenticate the user (https://github.com/dingo/api/blob/master/src/Auth/Auth.php#L151) that will try to use each provider available (https://github.com/dingo/api/blob/master/src/Auth/Auth.php#L82) to do so. This authenticate function expects as parameter 2 the current route (that doesn't exist remember?).

So the function $this->router->getCurrentRoute() called as parameter 2 take us to Router.php calling $this->createRoute($route) (https://github.com/dingo/api/blob/master/src/Routing/Router.php#L691) that creates a new Route object (https://github.com/dingo/api/blob/master/src/Routing/Router.php#L713).

In this point tracking the Route object and its construct method it calls $this->setupRouteProperties($request, $route) (https://github.com/dingo/api/blob/master/src/Routing/Route.php#L144) that calls $this->mergeControllerProperties() (https://github.com/dingo/api/blob/master/src/Routing/Route.php#L167) that finally calls $this->makeControllerInstance() (https://github.com/dingo/api/blob/master/src/Routing/Route.php#L186).

So makeControllerInstance method is making a new instance of our controller (https://github.com/dingo/api/blob/master/src/Routing/Route.php#L325) that's call our __construct method again, that fires $this->user() again, and the stack begins again.

This will be recursive until the max stack on nesting level in xDebug be reached that for you is 200 (but for me is 256). BTW you can deactivate xDebug or set the maximum nesting level in the php.ini higher using xdebug.max_nesting_level=500 for example.

So this proves that you can't use $this->user() on __construct method.

But the real question is WHY you need to use that or even set it to a user property when the Helpers trait dynamic offers you that user property by magic method __get as an alias for user() method?

@tembra Thx from your great explanation.

I did not know that "user" property exists (magic method), so I had more methods in the controller that I need the "user" object, that's why I initialized the user property to user method.

Excellent explanation @tembra, thanks for your replies to many of these issues. Very helpful. :+1:

I do need to clear a lot of these little confusing errors up though by noting it in the docs. One day.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

cristiammercado picture cristiammercado  路  3Comments

adrian-fjellberg picture adrian-fjellberg  路  4Comments

sukh-gill picture sukh-gill  路  3Comments

MicroDroid picture MicroDroid  路  3Comments

pongz79 picture pongz79  路  4Comments