XF 2.2 How to set multiple route Actions in the same Controller?

alexAlToader

New member
Hi,

I have problems understanding how to create 2 actions in the same controller.
I need to save 2 routes in Admin for the 2 actions - right?

For the first route I dont have anything specified and it resolves at actionPost.
However, when I try to add another route in the same controller, I cant figure out what I need to change to have a route Action named "randomActionName"

I tried adding randomActionName as a Sub-name or as an Action prefix - still not working.
I also tried to add "action" in front of "randomActionName" or "Post" after "randomActionName" - still not working.

Please help!
 

Kirby

Well-known member
Normally you need only one route, a perfect example is misc.

misc calls actionIndex(), misc/contact calls actionContact(), etc.
 

alexAlToader

New member
Right. So you are saying that the action is the second parameter after the controller - which does not appear anywhere in the definition of the route in admin.. ok thanks let me test.
 

alexAlToader

New member
So

$response = Http::withHeaders([
'XF-Api-Key' => self::API_KEY
])
->asForm()
->post(self::API . 'register/confirm', []);

Should map to

public function actionConfirm()
{
echo '2222'; exit();
}

But I am getting:

{#457
+"errors": array:1 [
0 => {#453
+"code": "endpoint_not_found"
+"message": "Requested endpoint cannot be found."
+"params": {#460
+"reason": "invalid_action"
+"debug_reason": "invalid_action" ...
+"debug_action": "Postconfirm"
}
}
]
}

What am I doing wrong pls?
 

alexAlToader

New member
Ok I see so I could use that endpoint instead of creating a new endpoint - which I was trying to do.

However - how can I solve the action issue pls? It is something which I need to clarify.
As I said - in that controller, the register -> actionPost works but the register/confirm -> actionConfirm is bringing that error...
How can I debug it - must be some typo or something as I understand this must work out of the box.

How can I see what is the name of the Action xenforo is looking for pls?
 

Kirby

Well-known member
Can you post you whole code for the controller?
And a screenshot of your route definition?
What's the value of self::API?
 

alexAlToader

New member
The xenforo code:

<?php

namespace extendedApi\Register\Api\Controller;

class Register extends \XF\Api\Controller\AbstractController
{

public function actionPost()
{
echo '1111'; exit();
return 'xenforo actionPost';
}

public function actionConfirm()
{
echo '2222'; exit();
return 'xenforo actionPost';
}

}

then the Laravel code:

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

use Illuminate\Support\Facades\Http;

/**
* Class RegisterController.
*
* @package App\Http\Controllers\Auth
*/
class RegisterController extends Controller
{

const API = 'http://cms.local/api/';

const API_KEY = '[somekey]';

public function registerConfirm(Request $request)
{

$response = Http::withHeaders([
'XF-Api-Key' => self::API_KEY
])
->asForm()
->post(self::API . 'register/confirm', []);

return $response;
}
}


and the route definition


Thanks for looking into this
 

Kirby

Well-known member
API controllers are slightly different than Public/Admin controllers - their action methods distinguish between GET and POST.

XF\Api\Mvc\Router::routeToController()
PHP:
// Prepend the request method to the action. This is done here instead of in dispatching as doing it there
// makes it difficult to reroute to controllers (such as for errors).

if ($request)
{
    $requestMethod = preg_replace('#[^a-z]#', '', strtolower($request->getRequestMethod()));
    if (!$requestMethod)
    {
        $requestMethod = 'get';
    }
}
else
{
    $requestMethod = 'get';
}

$match->setAction($requestMethod . $match->getAction());

So basically you just have to prepend the HTTP request method to your action method:

PHP:
public function actionPostConfirm()
{
    echo 'actionPostConfirm();'; exit();
}

public function actionGetConfirm()
{
    echo 'actionGetConfirm();'; exit();
}

To test:
Code:
curl -H "XF-Api-Key: <key>" -H "XF-Api-User: <userid>" -X GET http://cms.local/api/register/confirm
curl -H "XF-Api-Key: <key>" -H "XF-Api-User: <userid>" -X POST http://cms.local/api/register/confirm
 

alexAlToader

New member
Thanks @Kirby it works.

So the docs at https://xenforo.com/docs/dev/routing-basics/#controller-actions
Should be something like this:

When adding a route in the Admin -> Development -> Routes

Route Prefix - is the visible URL part of the route
Sub-name - not sure (no docs) - maybe still visible part after the Route Prefix
Route format - where we define and capture the parameters from the route
Controller actions - they dont appear in the Routes panel - they work as follows
  • Default action: When calling the route as defined in Route Prefix - it matches automatically to actionIndex | actionPost | actionGet
  • User defined Action: When calling the route as Route_Prefix / anotherUrlSection - it matches to:
- if Public - actionAnotherUrlSection
- if API - actionPostAnotherUrlSection / actionGetAnotherUrlSection
Section context - no docs - dont know yet what they do
Action prefix - looks like you can put anotherUrlSection here but is not matching an action - but is part of the route only that you can have multiple segments with parameters?

Did I get it right?
 

Kirby

Well-known member
Sub-name is used if a route does handle multiple things.

An example would be admin route prefix logs.
This route prefix does handle all kinds of logs, so Sub-name determines which kind of log, like logs/spam-trigger.

Section context defines the navigation context to hinghlight if the route is accessed (eg. Tab for public routes or Accordeon menu section for Admin routes); it is not being used for API routes.

Action prefix is used in conjunction with Sub-name and defines what does get prepended to the action to build the method name, eg. logs/spam-trigger would prepend spamTrigger to the action.

admin.php?logs/spam-trigger => XF\Admin\Controller\Logs::actionSpamTrigger()
admin.php?logs/spam-trigger/1/ => XF\Admin\Controller\Logs::actionSpamTrigger() with param trigger_log_id set to 1
admin.php?logs/spam-trigger/1/view => XF\Admin\Controller\Logs::actionSpamTriggerView() with param trigger_log_id set to 1

HTH
 
Top