Trying to use a Route List in a package and getting an error that looks deep in Concrete code

I’m getting some help from a much-more-senior-than-myself Developer (I honestly don’t even consider myself a developer, shhh don’t tell anyone I maybe am ish!), and so I don’t really fully know how to represent this but…

We’re using a route to trigger some php stuff to execute when a user clicks on a button (the rationale and details probably aren’t of any help to the actual problem here). And my buddy has given me a bunch of code changes to make this happen.

So far as I can tell the method we are using is in-line with the Concrete CMS documentation, however when we click the button to execute the Route (and the relevant API) the result is a PHP Debug error I am having a hard time making sense of…

FYI, this is a dev environment, running Concrete CMS v8.5.7

“Call to a member function on_start() on string”

referring to: https://github.com/concretecms/concretecms/blob/8.5.x/concrete/src/Routing/ControllerRouteAction.php Line 57

===

Now, I’m really not even sure where to begin debugging this or identifying what on earth we/I did wrong to get to this result, since the error doesn’t even refer to any of the code that I/we wrote. I suspect something about how we’re invoking things is leading to this, but considering that “ControllerRouteAction.php” file hasn’t been modified AT ALL (in any version of Concrete CMS) since before the version of Concrete CMS I am running… I suspect this probably isn’t a bug, and probably is “user error”.

So… I’d love to give more info, but in this case I again really don’t even know where to begin.

pls halp D:

Yeah trying to “reverse-engineer” (hah) how I got to this point (namely the relevant php file and even API documentation) I actually see zero reason this should fail, and can’t even actually see how the “execute(…” function in ControllerRouteAction.php even comes to be.

I’m so out of my depth here @_@

@andrew I think we might need your deep knowledge on this one :confused:

Did you try using xdebug? It’s a real problem solver and life saver tool

It looks like on line 53 $controller is a string, not an object. On line 56 the function method_exists checks to see if the method exists in the class that your string points to, which it does.

You need to get a new instance of the class as an object before you run line 57.

Sure, but that’s a core Concrete CMS file which is completely unmodified, and not written by me. Which is also part of why I don’t know what is causing this, as I have not modified any core Concrete CMS code around any of this at all! So, I roughly already was able to gleam that information from reading it backwards, but it doesn’t get me anywhere productive. I don’t even know how that function is getting invoked, since well… it’s not my code and all that :stuck_out_tongue_winking_eye:

I don’t know anything about xdebug at all, plus the error points to core Concrete CMS code. None of which was modified by me, so yeah as I mentioned that’s part of my confusion. Since I don’t know how it’s being invoked, or why the error even referring to something I didn’t change at all. I wouldn’t even really know where to begin with xdebug, let alone get my arms bloody with deep Concrete CMS code (which I realistically do not know to any proper degree).

Sure, it’s an error in a Concrete file.
But it’s you that are maybe passing something wrong to Concrete.

Xdebug is a tool that can be used, for example, to suspend the execution of PHP at a certain point and see the value of the variables, as well as the call stack.

I’ll take a stab at it, but I’m also hoping any other ideas from others boil up in this thread. This really is a good lot out of my wheel house.

Yeah so reading into how to use xdebug this is very much beyond my experience to do correctly. Can we instead please work through how this error could come to be? Like, my current usage of Routing/RouteList is not high in complexity at all, and comparing it versus documentation does not show anything written incorrectly.

Me going down the xdebug avenue really is going to take a huge amount of time (a week or more?) for me to even understand how to use it at all, let alone correctly, or even reach a useful position. I’m not a developer “proper” so this is nowhere near a trivial thing for me to step into (xdebug).

Can we at least start somewhere in the code I have to explore what could be the matter? It seems plenty reasonable to get the expertise of the Concrete Devs who actually wrote this code, instead of me brute-forcing my massive ignorance on the debug tooling alone, let alone the additional massive ignorance on the core Concrete CMS code base.

I guess here’s some starter insights that may or may not be helpful… (this is in a package btw, most of the package stuff is Block Templates):

/controller.php, in the on_start() section:

        // Routing, related to RouteList and RouteList.php stuff above
        $router = $this->app->make('router');
        $list = new RouteList();
        $list->loadRoutes($router);

/controller.php, in the root section (before class Controller extends…):

use redacted\redacted\RouteList;

/src/RouteList.php:

<?php
namespace redacted\redacted;

use Concrete\Core\Routing\RouteListInterface;
use Concrete\Core\Routing\Router;

//Temporary maybe lel
use Log;

use redacted\redacted\Tickets\TicketManagementController;

class RouteList implements RouteListInterface
{
    public function loadRoutes($router)
    {
        Log::addInfo('redacted');
        $router->post('/api/tickets/applyTicket', [TicketManagementController::class, 'applyTicket']);
    }
}

-Template calling the API endpoint:

<form id="redacted" action="/api/tickets/applyTicket" method="post">

/src/Tickets/TicketManagementController.php:

<?php

namespace redacted\redacted\Tickets;

use Concrete\Core\Controller\AbstractController;
use Concrete\Core\Http\Request;
use Concrete\Core\Http\Response;
use Concrete\Core\Http\ResponseFactoryInterface;
use Concrete\Core\User\User;

class TicketManagementController extends AbstractController  {

    /**
     * The currently logged in user.
     */
    private User $user;

    public function __construct(User $user) {
        $this->user = $user;
    }

    /**
     * Applies a ticket to the user provided in the request.
     */
    public function applyTicket() {

        if (!$this->user === null || !$this->user->isRegistered()) {
            // Will redirect the user to the login page, and on successfuly login back to
            // where this post came from.
            return $this->getResponseFactory()->forbidden($this->getRequest()->getReferer());
        }

        // Inputs
        $ticketid = $this->getRequest()->post('redacted');
        $applyRedacted =  $this->getRequest()->post('redacted');
        $applyRegRecId =  $this->getRequest()->post('redacted');

        // Fetch
        $regRecTargetEntry = Express::getEntry($applyRegRecId);
        $modTicket = Express::getEntry($ticketid);

        // Update
        $modTicket->setAttribute("redacted", false);
        $modTicket->setAttribute("redacted", true);
        $modTicket->setAttribute("redacted", $applyRedacted);
        $modTicket->associateEntries()->setRedacted($regRecTargetEntry);

        // Go back to where you came from
        return $this->getResponseFactory()->redirect($this->getRequest()->getReferer(), Response::HTTP_FOUND);
    }

    private function getResponseFactory(): ResponseFactoryInterface {
        return $this->app->make(ResponseFactoryInterface::class);
    }
}

I think that’s everything relevant?

It would appear to me that you are looking for some paid help at this point. Why not post this in the jobs part of the forum and I am sure if paid there are a few people that would happily help you.

You might find a better outcome.

People come to the forums asking for help with code all the time. And the reason that I pasted what I have is to demonstrate that I’m barely using more than what is documented as the minimum in the Concrete CMS official documentation. And that the behaviour of the, in my observation, seemingly default basic behaviour from that documentation, is not working.

That is not the same as asking for paid help to write code for me in totality or anything like that. I’m here asking for help with only a portion of my code, you know, since this is literally a help section of the forums.

But yeah, for decades people have come to the Concrete forums asking for help with all kinds of different code, and a good chunk of it far more complex/involved than what I pasted above.

I’m not asking for help for the parts that execute when the API is called, (as in the PHP code modifying Express stuff). I’m asking for help with the Routing aspect as the documentation sure looks to be generally accurately followed by the code.

If you @TMDesigns do not see an area that I’m making a mistake (and want to point it out), or are not interested in trying to help me with this, well that’s your choice and so be it. But my ask for help is reasonable and in-line with how so many others have come to these forums for help of generally the same kind.

So yeah, no, I am not looking for “some paid help at this point”, I actually am hoping one of the Concrete CMS devs can chime in, because the documentation followed does not look to be producing the expected, “basic”(ish), results. And I am out of ideas, hence asking for help.

I’m not sure if this will do the trick, but have you tried changing your src/RouteList.php to use strings instead of an array to map to the controller?

instead of

$router->post('/api/tickets/applyTicket', [TicketManagementController::class, 'applyTicket']);

could you try:

$router->post('/api/tickets/applyTicket', 'redacted\redacted\Tickets\TicketManagementController::applyTicket');

and see if that does the trick? It looks like this would be closer to the docs: Controllers :: Concrete CMS

Failing that, since you mentioned it is a dev environment can you paste a full stack trace of the error as that may give a clue where it’s originating from (if it doesn’t include any sensitive info you do not want public).

1 Like

AHA!!! I think you’re onto something here!!! I adapted your proposed change from Array to uhhh… not sure what term to use but effectively the method you proposed, and I’m pretty sure I’m getting farther! Now it’s complaining about my code within the API action :wink: I think I may have forgotten to “use” an Express library. I THINK this did the trick, but I’m going to try and fix this other error I have now (that is probably my fault) and aspire to ring back with more results and such!

Either way, thanks a whole bunch! Yay! :DDD I’m going to hold off marking your proposition as a solution until I handle the other silliness (again that’s probably my fault) first, so I can be sure it did the trick! :slight_smile:

@triplei Alright so I’m now confident your proposed adjustment is what did the trick, thanks! Marked your response solution and all that.

That being said, I’m stuck at a new part (in the TicketManagementController.php file), and if you have any ideas please let me know. If not, well no worries!

return $this->getResponseFactory()->redirect($this->getRequest()->getReferer(), Response::HTTP_FOUND);

Error:
Call to undefined method Concrete\Core\Http\Request::getReferer()

===

Now, this part was written by the aforementioned much-more-senior-than-myself Developer, so I can’t speak to the intent fully on what this line is meant to do. But if you or anyone has any ideas, I’m all ears! :slight_smile:

Again, thanks! Yay! :smiley:

Read more into the latest issue, missing method for the “class” (right term?), trying to figure out best method to pass referer value in the redirect() part. Not yet seeing one in Concrete CMS land, and a method I found ( How do you get the 'referer' header in PHP? - Stack Overflow ) using “$_SERVER[‘HTTP_REFERER’]” I might try, but that thread speaks about how it isn’t ironclad as a method. Trying to see if I can dig up a better way, but might try that anyways… hmmm…

Yup, “$_SERVER[‘HTTP_REFERER’]” method works, but I’m seeing a lot of concerning discussion over the years (across the internet) that it’s not a secure method. So considering this is for a function that security would be a concern, I’m going to try to find a method. But yeah pretty sure the original issue and such is solved now.

Thanks again! Yay! :smiley:

For future humans, I am going to try this method instead : Session handling and GDPR :: Concrete CMS

In tandem with: PHP get current page URL - concrete5

In that I’m going to try $c->getCollectionLink() for the page where this API is being called from, stuff it into a Session variable (as outlined above), then use that instead of $_SERVER[‘HTTP_REFERER’] to hopefully strongly protect against referer tampering.

edit: updated session example URL with one from 2019, previous example was from 2015, so new one hopefully is more currently relevant, heh.