0

To call a controller I use a CURL request like this:

curl -kX POST https://site/method  -H 'Authorization: Bearer ACCESS_TOKEN\
Content-Type:application/json' -d '
{
    "param1":"value 1",
    "param2":"value 2",
    "param3":"value 3"
}'

The route calls UserController@method.

How can I do the same from Laravel code (internal request, not sending CURL)?

I've found an advice to use something like this

        $controller = app()->make($controllerName);
        $response = app()->call([$controller, 'method'], []);
        echo $response;

where the last [] should contain some parameters. But if this is the way, I cannot figure out how the array should look in my case.

P.S. Please, don't answer "it's a bad practice" instead of giving an advice how to implement what I need.

AHeavyObject
  • 562
  • 1
  • 7
  • 18

2 Answers2

1

Here is my solution (Laravel 5.4). Inspired by https://stackoverflow.com/a/40366119/518704 but needed much time to dig into the code to find how to pass my Authorization: Bearer token

I need this approach to authorize in a browser-less socket connection (Ratchet), where JS code is not running. So I could not use Ratchet WebSocket, only simple socket Ratchet IoServer. My API controller returns JSON so it's easy to work with the response further. I need this approach mainly to authenticate the socket connection assuming the client knows the access token when one opens the socket (got by REST on login).

First of all I need to use a trait, used in Tests

Next in onMessage code I assume a JSON message is passed with the access token. To simplify here I don't write JSON validity check etc.

namespace App;

use Ratchet\ConnectionInterface;
use Askedio\LaravelRatchet\RatchetServer as RatchetServerBase;

class RatchetServer extends RatchetServerBase
{
...
    public function onMessage(ConnectionInterface $conn, $input)
    {
          $input = json_decode($input);
          $token = $input->token;


          // Some data (may be taken from JSON $input)
          $data = [
            "param1" => "value 1",
            "param2" => "value 2",
            "param3" => "value 3"
          ];

          // Prepare the server headers
          $server = ['HTTP_AUTHORIZATION' => 'Bearer ' . $token];

          // This way! If calling app() here, it reuses the same Auth::user() 
          $app = require __DIR__.'/../bootstrap/app.php';
          $kernel = $app->make(\Illuminate\Contracts\Http\Kernel::class);
          $response = $kernel->handle(
              $request = \Illuminate\Http\Request::create('/user', 'GET', $data, [], [], $server)
          );
          // ~ var_dump(Auth::id());
          $controllerResult = $response->getContent();
          $kernel->terminate($request, $response);

          // My controller hidden under /user route is an API one and returns JSON string
          echo $controllerResult;
    }
...
}

My previous solution didn't work. The Auth::user() always returned the first logged in user (app() seemed to use singleton). So I leave the previous code for reference purpose.

namespace App;

use Ratchet\ConnectionInterface;
use Askedio\LaravelRatchet\RatchetServer as RatchetServerBase;

class RatchetServer extends RatchetServerBase
{
    use \Illuminate\Foundation\Testing\Concerns\MakesHttpRequests;

...
    public function onMessage(ConnectionInterface $conn, $input)
    {
          $input = json_decode($input);
          $token = $input->token;

          $data = [
            "param1" => "value 1",
            "param2" => "value 2",
            "param3" => "value 3"
          ];

          // The 2 lines below can me moved to the __constructor method
          $this->baseUrl = request()->getSchemeAndHttpHost();
          $this->app     = app();

          // Prepare the server headers
          $server = ['HTTP_AUTHORIZATION' => 'Bearer ' . $token];

          // Call my controller by route (this seems to be internal call)
          $response = $this->call('GET','/method', $data, [], [], $server)->json();
    }
...
}

P.S. Just a note for myself when I come here later. Too see available headers and proper naming I did a var_dump in for $this->parameters ./vendor/symfony/http-foundation//ServerBag.php

AHeavyObject
  • 562
  • 1
  • 7
  • 18
0

I do not see a simple solution to do this. It's not a good idea to call a controller from other methods. The controller responds to the request and should not be used as trivial class. If you need to test the controller, laravel provides methods for testing, including calling the controller. https://laravel.com/docs/5.4/testing. If you need to call some method in several places - better define it in model, or repository and then call it where you want.

Nutscracker
  • 702
  • 3
  • 9