Roots Discourse

Calling Controller (App.php) functions from setup.php (and other controllers)

Hello.

I updated to the latest Sage 9.0.4 and was wondering what happened with the Controller update: I can’t seem to call App::myFunction() from within setup.php anymore? This worked in previous releases, but perhaps it’s wrong to do that in any case.

How can I properly access those methods here?

Just for better understanding, I’m doing something like this for example in setup.php:

/**
 * Theme assets
 */
add_action('wp_enqueue_scripts', function () {
    wp_enqueue_style('sage/main.css', asset_path('styles/main.css'), false, null);
    wp_enqueue_script('sage/main.js', asset_path('scripts/main.js'), ['jquery'], null, true);
    $script_params = array(
        'theme_dir_uri' => App::themeDirURI(), // this worked in previous Controller versions
        'ajax_url' => App::ajaxURL(),
        'ajax_nonce' => wp_create_nonce('my_nonce'),
        'home_url'     => home_url(),
        'translations' => array(
            'back_to_top' => __('Back to top', 'my'),
            'back_to_home' => __('Back to home page', 'my')
        ),
    );
    wp_localize_script('sage/main.js', 'GLOBAL_OBJECT', $script_params);
}, 100);

Now using App::myfunction() throws: Call to undefined function .. so I’m clearly doing something wrong from the start.

Thanks!

Hi @trainoasis,

It’s due to the namespace change. If you are using static functions outside of Blade templates, then you need to use the correct namespace. From Controller 2.0.0, PSR4 autoloading is used. So the full namespace for a Controller file is now App\Controllers\

So, in this case, seeing as setup.php is in App namespace, you would use Controllers\App::themeDirURI(). The Controller loader removes the need for this namespace in Blade templates, so there you can simply reference the Controller class name and the static function.

Let me know if that makes sense.

2 Likes

That’s exactly what does it @withjacoby, thank you.

I wasn’t sure where I would figure this one out to be honest.

@withjacoby if you would be so kind, the same issue arises inside custom controllers, for example

public static function makeFlexibleContent()
    {	
    	$data = self::getJumboData();
    	echo Template('components.dynamic-template.jumbotron', $data); 

Template() function not working. Gotta get the correct namespace but am not sure how to proceed or where to find it? How do you know what to add there? Wanna know for the future issues that I’ll have, don’t just wanna ask you every time if possible :slight_smile:

Am totally at a loss here, tried various Controllers\App namespace variations, to no avail. (of course, not knowing how namespaces work here is not helping).

I’m not sure what you are trying to accomplish here, but there is no function called Template() in Sage. Do you mean template()?

Perhaps you could explain the end goal and I can help from there.

1 Like

Here’s a reply I wrote a bit ago that might help you out with understanding namespaces: Controller namespace issue, different behavior on localhost and development server (solved?)

Finding out what namespace a class, method, or function is in is generally pretty simple:

  • Find the file where the function/method/class is defined
  • Go to the top of the file and look for namespace
  • If you’re looking for a…
    • function then that’s it, just prepend the namespace when calling the function
    • class then that’s it, just prepend the namespace when calling the class
    • method then you’ll need to prepend the namespace, then class, when calling the method

Take the example file below:

<?php

namespace Roots;

class Sage {
    public static function hello()
    {
        return 'hello from a method';
    }
}

function goodbye()
{
    return 'goodbye from a function';
}

To instantiate this class in another file, you would write:

$class = new Roots\Sage();

To call the static method hello() from another file, you would write:

$greeting = Roots\Sage::hello();

To call the function goodbye() from another file, you would write:

$farewell = Roots\goodbye();

If the other file has a namespace, and that namespace is not Roots, then you need to prepend a slash to all of your calls, i.e.:

$greeting = \Roots\Sage::hello();

That should be enough info to get you started.

6 Likes

I thought template() at first as well (function inside helpers.php), but am using Template() in my production code with previous Sage versions and it’s working as expected. I found that here on discourse some time ago, but here used to output shortcodes as @MWDelaney shows: https://discourse.roots.io/u/MWDelaney): Shortcodes that use Blade templates and get Controller data. I do admit I don’t know where this functions comes from.

It helps when outputting template code from Ajax or when you want a function that you can use that outputs the whole view based on controller info.

Does that make any sense or am I abusing certain paradigm?

Thanks, that’s very helpful. It seems my main issue is I don’t know where Template() comes from. There’s template() in helpers.php, but on my live site Template() works without seeing any Template() anywhere. Perhaps I’m just missing some knowledge there :slight_smile:

Follow up: made it work using your instructions: current file has namespace App\Controllers; and thus I had to move to a different namespace using prepended slash so \App\Template() does work!

Didn’t know you can use Template() OR template() and both work.

Thanks for your quick lecture, love it.

1 Like

Thanks @withjacoby, made it work using \App\Template(). It seems both template() and Template() work, although I do not know why.

Didn’t know I can move to a different root namespace using prepended slash, so there you have it.

If you do know about naming conventions and why both functions work, please share :slight_smile:

Thanks for your time!

Glad to hear! No problem.

hello guys,

following your hints, I was trying to call a public function written in a controller from another component:

Contatcs.php has

namespace App\Controllers;

use Sober\Controller\Controller;
use \WP_Query;

class Contacts extends Controller
{
    public function getSocials()
    {
       ...
            return $socials;
        }

    }

}

works fine from within template itself: $socials = Contacts::getSocials();

now I wand to call it from footer.php:

$socials = \App\Controllers\Contacts::getSocials();

but it seems it’s not giving any sing of life :frowning:

ty!

Why are you trying to do this? The point of a controller is to pass data to the view, not to be a container for methods. It’s not working because that controller isn’t loaded in the context of your footer. If you want that data in the footer, pass it in a controller that makes data available to the footer (ie App).

hello,

so how to create “common” methods to avoid replicating function in every controller?

this is a hybrid case, as I noticed I could recycle a function I created in a specific controller and thought to re-use it, withtout copying/pasting in the proper controller.

can we go through this?

When the helper function is very theme-specific I put them in the app/helpers.php (Sage 9/10).
When the helper function has a scope too broad, it may make sense to add it to a separate library that can be required by the theme as composer dependency (not to be confused with a WordPress plugin).

ty @strarsis sounds like the thing I was trying to do :slight_smile:
but actually didn’t get you 100% :stuck_out_tongue:

I have an helper.php file in /app/ folder.
are you saying I should work there and then call the function from within such file?