Controller namespace issue, different behavior on localhost and development server (solved?)

Having a conundrum here.

Updated to the latest Sober Controller and my localhost instance works fine. However, when pushed to the development server I get the following error:

Fatal error: Uncaught ReflectionException: Class App\Controllers\app does not exist in /data/www/truthout4-dev/public_html/wp-content/themes/truthout4/vendor/soberwp/controller/src/Loader.php:119

Reading up on namespacing I see I used namespace App; rather than namespace App\Controllers;, (odd though that it works on localhost) so I fixed that error and pushed again.

However that generates the error:

Uncaught Symfony\Component\Debug\Exception\FatalThrowableError: Class 'App' not found... for any template calling on an App function, both on localhost and the dev server.
`

But app.php has it defined:

namespace App\Controllers;

use Sober\Controller\Controller;

class App extends Controller

I thought I’d followed the instructions correctly, but I’m new to the Sober Controller and it’s still a bit of a mystery to me. What am I doing wrong?

2 Likes

You didn’t give an example of a function you’re trying to call that’s failing, but since you said " for any template calling on an App function" I assume you mean something like App::siteName(). If that’s the case, you would need to change those to (probably) something like Controllers\App::siteName(). When you change the namespace, you need to change any calls to classes in that namespace.

I tend to think of namespaces kind of like directories: When you’re in a namespace/directory then you can “see” everything in that namespace/directory easily, but anything in another namespace/directory needs instructions on how to get there appended to it.

If I’m on the command line and I want to call a function in the directory above my current working directory, I’d do something like this:

bash ../distant-script.sh

But if I wanted to run a script inside my current directory, I’d just do this:

bash adjacent-script.sh

Namespaces work the same way: If I’m in the App\Controllers namespace and I create a class called FrontPage, I can get at in a couple ways. if I’m “in” the App\Controllers namespace (that is, I’m executing code in a file that begins with namespace App\Controllers), then all I have to do is this:

new FrontPage();

But if I’m in the App namespace, then I have to do this:

new Controllers\FrontPage();

Or if I’m in the AlwaysBlank\Tools namespace, I would have to do this:

new \App\Controllers\FrontPage();

(Just like in directory navigation, \ at the beginning of your namespace will return you to your “root”).

Hopefully that helps.

Thanks,

Yes, I am calling the function via {!! App::site_logo() !!}.

This is as instructed by the Sober Controller documentation, which states that for namespace namespace App\Controllers; the template function would be {{ Archive::title() }}.

I’m using {!! !!} instead of {{ }} because I had issues with escaped html showing in post titles, though for this particular instance I could switch back.

We’ve change both the namespaces and the template functions to both have \Controllers, and now we’re getting PHP errors stating the ACF fields are undefined. It’s as if Sober isn’t populating the variables.

We’re still experimenting and the next step will be to downgrade the controller and see if that’s the issue.

1 Like

We have a work-around, sort of.

I have two files in app/controllers/, app.php and FrontPage.php.

I have to create a new folder called app/Controllers/ with a capital “c” and duplicate both files into capital-C Controllers.

If both files are not in both folders, the site breaks.

One folder works fine on all our dev systems which are Macs because HFS+ is a case-insensitive file system. But on linux, which is case sensitive, both folders must be present.

We appear to be using the proper class naming and function call formats as per the Sober Controller documentation.

I haven’t yet sourced the actual problem. We upgraded to Sober Controller 2 at the same time we moved many functions from a plugin to the controller and I’m not sure which change introduced the error.

Looks like a known issue:

Changing the folder name to “Controllers” is probably (?) the correct solution, since then your stuff would be correctly named for PSR-4. The strange thing is this part:

Linux shouldn’t require both folders. This makes me think that maybe (?) your deployment process is pushing a composer autoloader file that was generated on a Mac w/ HFS+, and is now causing problems because the paths, etc, it encoded were not case-sensitive.

Can you run composer dumpautoload on one of your Linux machines and see if that allows you to delete the lower-case “controllers” directory?

composer dumpautoload returns one string, “Generating autoload files”. I don’t otherwise see that it’s output any new file. I read the docs and it seems like it generates a file at vendor/composer/autoload_classmap.php, and reading through that file on both Mac and Linux shows nothing but sniff files and no mention of app or controller directories.

After running composer dumpautoload, I deleted the files in controllers (lower case) and get the following errors (the first two relate to an ACF field variable not being assigned):

PHP Notice: Undefined variable: to4_custom_content...
PHP Warning: Invalid argument supplied for foreach() in...
PHP Fatal error: Uncaught Symfony\Component\Debug\Exception\FatalThrowableError: Class 'App\Controllers\App' not found
(plus some stuff in stack trace)

If I delete the files from Controllers (upper case) I get the errors:

"PHP message: PHP Fatal error: Uncaught ReflectionException: Class App\Controllers\app does not exist...[path to Loader]
Stack trace: #0 /data/www/truthout4-dev/public_html/wp-content/themes/truthout4/vendor/soberwp/controller/src/Loader.php(119): ReflectionClass->__construct('App\\Controllers...')

I don’t know if it matters but somewhere in troubleshooting this we altered the template calls to this format, as instructed by some older thread:

{!! App\Controllers\App::siteLogo() !!}

Pushed again, problem is solved.

No clue what went wrong.

Just fixed this same issue by bumping soberwp in composer.json

from
"soberwp/controller": "dev-master"

to
"soberwp/controller": "~9.0.0-beta.4"

…seems to have fixed it.

Very odd though. Works in Development. Not on Staging.

:confused: :confused: :confused:

1 Like

In my case the problem seems to be a confluence of my deploy process and disk formats.

Changing the folder name from controller to Controller on Mac development boxes was no issue, but pushing to staging which uses a bare git repo and git checkout -f left resulted in both a controller folder and a Controller folder.

Deleting controller and re-running yarn build seemed to fix it.

When moving between files stems, git will not always behave in the way you might expect w/r/t case sensitivity. You can control how git handles that with the core.ignorecase setting. The git documentation elaborates a bit:

core.ignoreCase

If true, this option enables various workarounds to enable Git to work better on filesystems that are not case sensitive, like FAT. For example, if a directory listing finds "makefile" when Git expects "Makefile", Git will assume it is really the same file, and continue to remember it as "Makefile".

The default is false, except git-clone[1] or git-init[1] will probe and set core.ignoreCase true if appropriate when the repository is created.

If you need to change the case on a file/directory git is already tracking, you can use git mv, I. E.:

git mv uppercase UpperCase
2 Likes

git mv uppercase UpperCase didn’t work for me. Instead I used:

git rm Controller
git checkout controller
git mv controller temp
git mv temp Controller
git checkout Controller

This solved my dueling folders issues and fixed a number of build errors and hard crashes, yay!

However the strangeness isn’t done. None of my controller-assigned variables have values, including protected $acf = true; and public function someName().

$some_name and $some_acf_field are both set on localhost, and neither set on the linux servers.

But public static function someFunction() work fine even in the same controllers files where public functions are not working.

My Controller names are App.php, FrontPage.php, and Single.php as per Sober 2.0.0 instructions.

Added [core] ignorecase = false to my .gitconfig at your suggestion.

This issue is solved with Controller 2.0.1

composer update soberwp/controller

1 Like

Update:

Sometimes the above git dance didn’t work. Another working solution to change the filename case:

git mv controller temp
git add .
git mv temp Controller
git add .
git commit -m "fixed namespace again again"

Bashing my head here around the same issue as OP. Also on MacOS for dev.
I have updated to soberwp 2.0.1 with a composer require "soberwp/controller": "2.0.1".

After following the docs and updating namespaces etc… all worked well. Then one day on dev it didn’t.
In troubleshooting, template calls modified to {!! App\Controllers\App::title() !!} would work but not {!! App::title()!!}

The biggest issue is that I can’t get debug to work anymore?! The docs for 2.0.1 provide a seemingly nebulous usage: @debug which I assume is equivalent to the old @debug(‘dump’)?
Which in my blade app layout {{ @debug }} just echoes back ‘debug’. Old debug syntax yields debug() as an undefined function.

My app\Controllers\App.php is set up as follows:

namespace App\Controllers;

use Sober\Controller\Controller;

class App extends Controller
{
    use Traits\Promotions;

A public function calls a Trait and returns data to the blade variable.

public function controlPromotionsSlot1() {

    $result = Traits\Promotions::getPromotions(1, get_post()->ID );

My traits are loaded from app\Controllers\Traits\Promotions.php

namespace App\Controllers\Traits;

trait Promotions {

and up until now, I could access the blade variable in a view using the app layout like this:

@isset($control_promotions_slot1)
  @forelse($control_promotions_slot1 as $promotion)

@debug gets written on a line by itself exactly like it appears in the docs.

{!! !!} is a php echo, and @debug is like var_dump it doesn’t need to be echoed. When used on its own it will dump all variables to the screen with some nice formatting.

If you want the contents of one variable use @dump( $promotion )

I can’t speak to your Traits issue but maybe the debug will help.

Thanks scott. re: Traits issue i got that solved using the full namespace App\Controllers[Controller Class Name] such as App\Controllers\App::title() as opposed to the previously very convenient and brief App::title(). So solved but convoluted and poor readability.

On the debug side, when i just add @debug on a line by itself (no echo or curly braces), it just prints @debug on the frontend. However @dump($var) works fine with the nice formatting. I miss the @debug(‘hierarchy’) and @debug(‘controller’). Just appears to have vanished which makes debugging really unwieldy.

I’m not sure how you have your template configured. Is @dump inside a <?php declaration? Or perhaps there’s still a namespace issue caused by incorrect filename case?

I never used the old debug so I can’t really compare. @debug by itself has been very useful for me.

Quick update for closure’s sake. I ended up completely re-baselining my trellis/sage/bedrock install and that fixed the controller issues and the debug problem. I have NO idea what got corrupted where.

2 Likes