Calling controller function from ctp file

New to Cake and php. My background is in C++.

This question is two fold:

I have added a function to “ProductsController.php”:

class ProductsController extends AppController {

public function isAvailable($numProducts){
    if($numProducts > 0){
        $available = "Yes";
        return $available;
    }
    else{
        $available = "No";
        return $available;
    }
}

The file is otherwise in its default state, as baked.

I am then trying to call the function from Products/index.ctp:

<td><?= $ProductsController->isAvailable($product->stockAvailable) ?></td>

This is just a small project I have given myself after following the tutorial.

Alternatively, using the conditional operator in my .ctp file gets the desired result, however it seems a little messy:

<td><?= $this->Number->format($product->stockAvailable) > 0 ? 'yes' : 'no'; ?></td> 

Am I using cake properly, or have I made a silly, rookie error with my php/html.

Thank you kindly in advance,

Learning.

Hmm, yeah, you should study the CakePHP conventions and the MVC pattern a little more.

The basic idea is that your models should do the job of fetching data from the db, validating and preparing it for the controller.

In your controller, you can then do things like $this->Users->find(‘all’); etc.
In other words, retrieving the db data that has been prepared by the corresponding model. Then you can in turn prepare the controller variables for the view from within the controller.

This is intentionally a one-way-street; So if there’s something you need in your controller, you have to make it available from inside of the model first. And if you want something in your view, you’ll need to set it in the controller first (instead of returning it):

$this->set('myVar', '95.00 $');

That’s why unless you specifically set it, something like $ProductsController should not be available in your views. But setting the whole controller for the view isn’t sensible or possible in the first place; It’s kinda loopy and will shatter the space-time-continuum :smiley:

The important thing to understand is that your controller methods are “linked” to your views by default. So the isAvailable action could theoretically be accessed through the URL products/is-available and would throw an error because the view isn’t available.

In any case, it’s usually not desirable to add functions to controllers that aren’t supposed to be views.

Instead, you can create components for that, or even simpler, just put them inside your model tables and access them as easily as:

$this->Products->isAvailable()

However, you can’t access these in your views. To do so, you’ll need to use helpers. Create a helper like ProductsHelper" or whatever might seem best suited and add this function inside of it.

You can then use it in your views practically in the same way:

$this->Products->isAvailable()

(You can of course use cake bake to create the helper)

One possible issue with this is that helper methods aren’t accessible from inside the controllers and models. So if you have functionality that you need to use all across your app, you might consider adding it to the model as described earlier and then including it in your helper and simply creating wrapper methods for them:

use App\Model\Table\ProductsTable;

public function isAvailable() {
    return (new ProductsTable)->isAvailable();
}

I hope this makes sense. It’s might sound awkward if you’re new to CakePHP, but this structure is actually very helpful in keeping your app “disciplined” and DRY.

1 Like