Protecting access to a specific method of the controller - Cakephp 4

I want to create a method in a controller but I want it not to be accessible in the URL.

For exemple, I have a CheckoutController with a method to calculate shipping cost.

// in CheckoutController
public function _calculateShippingCost(): ?float
{
	return 8.00;
}

I think I’ve found a way to prevent this method from being accessible via its URL /checkout/calculate-shipping-cost (but still callable from a ShoppingCartComponent) by prefixing the method name with an underscore _.

I can’t find confirmation in the docs, is this a way to protect my method ?

Is there still a way to access this method that I would have missed ?

CakePHP only connects public methods inside controllers to URLs automatically (depending on what you have set in your config/routes.php)

So a quick fix for your would be to just change the method visibility to protected or private

BUT I would rather recommend you put that kind of business logic inside a service class so you have an easier time to re-use it wherever you need it.

I first set this method protected (as I plan to inheritate my CheckoutController) but it couldn’t be called from my ShoppingCartComponent anymore.
That’s why I set it to public.

The question is rather : Is there an URL (I hope not) that still can access to my method CheckoutController::_calculateShippingCost() as it is (e.g public and with underscore at the beginning of its name) ?

I tried /checkout/calculate-shipping-cost, /checkout/-calculate-shipping-cost, /checkout/_calculate-shipping-cost, … none of them is able to access but I might miss something…

Well if you already have a component why do you not put that method from the controller into the component?
Components are meant to be used by mutliple controllers so you don’t even have to deal with inheritance when doing that.

Because all this is inside a CommerceManager plugin that I’m creating, and I just need to override the method that calculates the shipping costs in my App.

And it is the easiest/clearest way I found to deal with inheritance.

// in CommerceManager/Controller/Component/ShoppingCartComponent.php
public function calculateShippingCost()
{
    return $this->getController()->_calculateShippingCost();
}

As CommerceManager.ShoppingCartComponent::calculateShippingCost() calls the current controller’s method _calculateShippingCost(), my App just has to inheritate CommerceManager.CheckoutController and override CheckoutController::_calculateShippingCosts() for rewriting the way the shipping costs are calculated.

If I would choose to put the shipping calculation only in CommerceManager.ShoppingCartComponent::calculateShippingCost() I can’t see how Component inheritance could work…

to come back to your original question: If you

  • can’t change the way how you build your app with controller inheritance but
  • don’t want those particular methods to be accessible as URLs

you can remove the $builder->fallbacks(); from your config/routes.php and manually connect each controller method with what URL you want.

Like

$routes->connect(
    '/users/view/*',
    ['controller' => 'Users', 'action' => 'view']
);

or

$routes->connect('/users/view/*', 'Users::view');

See the routing documentation for more details

But I still believe the better solution would be to de-couple your business logic from the whole controller system.

I will think about it, thanks.