Solved thread

This post is marked as solved. If you think the information contained on this thread must be part of the official documentation, please contribute submitting a pull request to its repository.

Directory Loader Not Registering Classes? (XAMPP/Windows)

EDIT:

Okay, I've figured out what the error related to the handler was, at this point I just need help getting my directory autoloader to work(the part of the code that's commented out), I'm on XAMPP under Windows, if that might play a role, I've tried absolute paths, relative paths, verified that __DIR__ points where I think it should, reversing the slashes(with escaping), and haven't gotten anything to load the classes automatically.

Using $loader->registerClasses works fine, so I know that the class is named properly and works, but for some reason it's not detected by the registerDirs autoloader.

Original Post:

So my directory structure is pretty simple:


/
    controllers/
        users.php
    api.php

My code is taken almost verbatim from the Micro section of the docs:

api.php:


<?php
$loader = new \Phalcon\Loader();

/*$loader->registerDirs(
    [
        __DIR__ . "/models/",
        __DIR__ . "/controllers/"
    ]
)->register();*/

$loader->registerClasses(
    [
        "UsersController"         => "controllers/users.php",
    ]
)->register();

$app = new \Phalcon\Mvc\Micro();

use Phalcon\Mvc\Micro\Collection as MicroCollection;

// Users handler
$users = new MicroCollection();
$users->setHandler(new UsersController(), true);
$users->setPrefix('/users');
$users->get('/get/{id}', 'get');
$users->get('/add/{payload}', 'add');
$app->mount($users);

$app->after(
    function () use ($app) {
        $app->response->setContentType('application/json');
        $app->response->sendHeaders();
        echo json_encode($app->getReturnedValue());
    }
);

try {
  $app->handle();
} catch (\Exception $e) {
    echo "Exception: ", $e->getMessage();
}

controllers/users.php:


<?php

use Phalcon\Mvc\Controller;

class UsersController extends Controller
{
    public function index()
    {
        return ["hai", "test"];
    }
    public function get($id)
    {
        return [$id, "testget"];
    }

    public function add($payload)
    {
        return [$payload, "testadd"];
    }
}

For one, I've commented out the Directory loading, because the UsersController class was failing to load, so I've loaded it directly just for testing.

Second, now that it IS loading, I get this error, regardless of what page I visit (/users, /, whatever):

Fatal error: Uncaught InvalidArgumentException: Parameter 'definition' must be a string in C:\Code\stud\xampp\htdocs\api.php:30 Stack trace: #0 [internal function]: Phalcon\Mvc\Micro\LazyLoader->__construct(Object(UsersController)) #1 C:\Code\stud\xampp\htdocs\api.php(30): Phalcon\Mvc\Micro->mount(Object(Phalcon\Mvc\Micro\Collection)) #2 {main} thrown in C:\Code\stud\xampp\htdocs\api.php on line 30

Anyone know why this isn't working? I'm using PHP 7.1.4 on XAMPP with Phalcon 3.2, I've tried using forward slashes(Windows problem?) and removing the first / to fix the autoloader, but still the class doesn't load, and I don't have any idea how to fix the above error.

First, you don't need to set json content type headers to send a json output, you can just use: $app->response->setJsonContent($data)directly from the controller. no need to use an after.

also, read the error message, on line 30 is the root of your error.

also echo "Exception: ", $e->getMessage(); the , should be a .

I'm also guessing this is line 30: $users->setHandler(new UsersController(), true);

the true is used to use lazyloading, and the error message is complaining that the constructor is expecting a string, but is receiving Object(UsersController). can you see where you've gone wrong?

edited Jul '17

Okay, I made those changes, however, it still doesn't explain why the autoloader isn't detecting my directories (I've checked that __DIR__ is indeed pointing to my web directory, and I've tried relative and absolute paths with and without it).

You are correct that is line 30, however, I am directly copying from documentation, under lazy loading:

// Users handler
$users = new MicroCollection();
$users->setHandler(new UsersController(), true);
$users->setPrefix('/users');
$users->get('/get/{id}', 'get');
$users->get('/add/{payload}', 'add');
$app->mount($users);

Are the docs wrong?

EDIT: I can confirm that the docs are at least half wrong, at the top of the Lazy Loading section, they properly put the class name in quotes, when using the additional true parameter for lazy loading, but further down when they "put it all together" for you they try to pass a class instead of a string, which is where this error occurs. I've submitted an update in Github.

So I'm still trying to figure out why my autoloader won't pick up the class in my directories(it's the section I commented out here), any ideas? I think it's likely XAMPP related but I'm unsure.

edited Jul '17

i think you want __DIR__ . /app/models

as you're learning download phalcon devtools and create a new micro project. you'll get a framework to analyse,

edited Jul '17

So I used phalcon project stud --type=micro and generated a micro project. I then copied my users.php controller file shown above into the models directory, since that's the only autoloaded directory in that project by default.

Here's the original skeleton's loader.php file, with an instantiation of my UsersController class added at the end to test it:


<?php

$loader = new \Phalcon\Loader();

$loader->registerDirs(
    [
        $config->application->modelsDir
    ]
)->register();

new UsersController();

This throws the following error:

Fatal error: Uncaught Error: Class 'UsersController' not found in C:\Code\stud\xamppTest\htdocs\stud\app\config\loader.php:14 Stack trace: #0 C:\Code\stud\xamppTest\htdocs\stud\public\index.php(32): include() #1 {main} thrown in C:\Code\stud\xamppTest\htdocs\stud\app\config\loader.php on line 14

However, if I simply use registerClasses and specify the file and class name, using the exact same directory:


<?php

$loader = new \Phalcon\Loader();

$loader->registerClasses(
    [
        "UsersController" => $config->application->modelsDir . 'users.php'
    ]
)->register();

new UsersController();

I get no error. Something is wrong with the registerDir function.

edited Jul '17

No there isn't. You need to beocme more self-sufficient and actually look at the mistake you're making! ;)

You're putting a controller class inside the models directory. Phalcon looks for models in the models dir, controllers in the controllers directory, migrations in the migrations dir etc as specified in the config. When you specifically define the location of the classes, it knows where to find the classes so phalcon doesn't need to look in the dirs - akin to Composers autodump i suppose.

Look in the config file for yourself. Add a config directory (though I think it may be there by default), and specify that the controllers dir exists inside the app config. application[ .... 'controllersDir' => APP_PATH . '/controllers', ....]



3.6k
Accepted
answer
edited Jul '17

The name of the folder is irrelevant, as I'm simply trying to load classes from that folder. Phalcon doesn't care if I put controller classes in the model directory, or if I rename the model directory to "cows", that's just a common practice, and as long as the code refers to the right folder it should autoload all classes, regardless of type, from that folder.

Doing what you said, creating a controllers folder in the config and referring to that, gives the same error as before.

Interestingly enough, your suggestion led me to a discovery, I simply changed the class name to "Users" (still extending Controller) and it now loaded the class properly.

However, if I changed it to ANYTHING other than Users, or if I deleted it completely and try to instantiate the Users class, I got an error.

So I finally figured it out, the issue is that the name of the php file did not match the name of the class. I looked and it is very briefly mentioned in the Autoloader docs:

The third option is to register directories, in which classes could be found. This option is not recommended in terms of performance, since Phalcon will need to perform a significant number of file stats on each folder, looking for the file with the same name as the class. It's important to register the directories in relevance order. Remember always add a trailing slash at the end of the paths.

Anyway, that was the issue, needed to name the file the same as the class.

Also, for anyone who finds this thread trying to figure out my original problem, I want to respond to the first post, as it has several inaccuracies:

First, you don't need to set json content type headers to send a json output, you can just use: $app->response->setJsonContent($data)directly from the controller. no need to use an after.

also, read the error message, on line 30 is the root of your error.

also echo "Exception: ", $e->getMessage(); the , should be a .

  1. Setting the content-type in the after section was because I would be doing so for all output, so putting it there reduced repetition across all controllers. (DRY principle), however, you are correct that the setJsonContent function was a better choice for this.

  2. Echo with commas for multiple strings is correct syntax as well. Concatenation is actually slightly slower

However, I do greatly appreciate you taking the time to continue responding, as your responses kept pushing me to test new things until I found the issue myself, so thank you very much.

edited Jul '17

i actually went to upvote this but missed and now can't change it! However downvoting my last answer was f'ing rude after all the time I've put in to replying.