Cphalcon: Class not found error when Controller has uppercase letters in class & its file name

Created on 27 Jun 2014  ·  43Comments  ·  Source: phalcon/cphalcon

I have setup Php 5.5, Phalcon 1.3.1 on 64bit Linux on a shared hosting server. I was able to run my application on Wamp on Windows 7 with Phalcon 1.3.1 & Php 5.5 but when I moved the application to production on a Linux 64 bit (most probably CentOS) I got the below error:

Fatal error: Uncaught exception 'Phalcon\Mvc\Dispatcher\Exception' with message 'CIAB\Controllers\ChooseprojectController handler class cannot be loaded' in /home/myproj/public_html/ciab/public/index.php:35
Stack trace: #0 [internal function]: Phalcon\Mvc\Dispatcher->_throwDispatchException('CIAB\\Controller...', 2)
#1 [internal function]: Phalcon\Dispatcher->dispatch()
#2 /home/myproj/public_html/ciab/public/index.php(35): Phalcon\Mvc\Application->handle()
#3 {main} thrown in /home/myproj/public_html/ciab/public/index.php on line 35

It looks like Phalcon doesn't allow uppercases in Controller class and file names except as the first letter. To get rid of this error I had to change the controller class name and the name of the file containing the class, i.e. ChooseProjectController.php, with a lower case 'P'. As mentioned earlier, it worked fine on Windows but on linux it didn't till I changed as above. You should easily be able to recreate this bug and it seems to be related to an older bug Error parsing annotations router #1040 bug. I am new to Github so I hope this is the correct way to inform you of a potential bug.

Regards

Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

not a bug

Most helpful comment

Guys, how is this not a bug? If the first character is uppercase, the rest can't just be bulldozed into lower case. Either you use camel case or you use some other standard. Forcing single-word controller names is just weird and counter intuitive. Naming convention is a big deal. Also, adding routes manually sounds very much like a workaround to me, rather than a proper solution. If there's implicit routing, it should use the same naming conventions as the rest of the framework.

Personally, I have a UrlCamelizer plugin that takes hyphened URLs (/choose-project) in accordance with Google's recommendations and converts to camel case for matching with the Controller / Action names. When the Controller name has been set, Phalcon rewrites my rewrites, breaking the URLs. This must be fixed, in my opinion.

Lastly, not to sound negative, I want to say that Phalcon is an AWESOME framework and I love it! Thanks for your hard work, Phalcon Team!

All 43 comments

Linux is case sensitive and Phalcon get the controller name, the first letter will be automatically converted to uppercase, other converted to lowercase.

I hope you consider this to be an issue and resolve it or is it that we can never define a controller class with multiple upper case letters in Phalcon.

I hope the devs consider this as not a bug. Phalcon handles this without any issue. But you must declare your classes in proper way - file name must be the same as the class name (case sensitive). There is a common pattern between various projects that uses this approach - class name corresponds to file name. And this shouldn't be altered.

It's annoying that Windows is case insensitive but it's not a bug in Phalcon anyway. Please follow good standards ;-)

I agree with you.
El 30/06/2014 3:27, Maciej escribió:

I hope the devs consider this as not a bug. Phalcon handles this
without any issue. But you must declare your classes in proper way -
file name must be the same as the class name (case sensitive). There
is a common pattern between various projects that uses this approach -
class name corresponds to file name. And this shouldn't be altered.

It's annoying that Windows is case insensitive but it's not a bug in
Phalcon anyway. Please follow good standards ;-)


Reply to this email directly or view it on GitHub
https://github.com/phalcon/cphalcon/issues/2572#issuecomment-47501901.

_Todo tiene su tiempo y todo lo que se quiere debajo del cielo tiene su
hora_

VII Escuela Internacional de Verano en la UCI del 30 de junio al 11 de julio de 2014. Ver www.uci.cu

_Jodator_, the issue is not how Linux / Windows treat the file names - you are right on that point. My class name and file name cases were the same. It should have worked on both platforms. I think Phalcon has an issue that it is doing some case conversion as _dreamsxin_ mentioned above. It should not. Doesn't Windows API return the file name to Phalcon as the actual case is? If it does, then there should be no issue. Let me know, if it is not a good convention to use camel case in file names or variable names in Php. I have shifted to Php from another programming environment recently.

@amsharma9 OK, maybe I misunderstood something reading your post, but in error you have that ChooseprojectController cannot be found so if you have ChooseprojectController.php and get this error then it is something wrong, but if you have ChooseProjectController.php then it's wrong class name or wrong file name.

As for naming I'm using camel case almost everywhere (with exception to view file names in volt) and I find it OK.

Thanks for clarifying. I will be specific - when I have ChooseprojectController in class and file name it works fine but when I have ChooseProjectController in both class and file name it doesn't work, because Phalcon is looking for a class ChooseprojectController in the latter case too - if I understand correctly, its an issue with Phalcon because it converts all controller class names to first letter uppercase and rest lowercase. Is that functionality of Phalcon acceptable. If yes, that implies I can never have a controller class like MyClassWithCamelCaseController because it will look for class MyclasswithcamelcaseController. Correct me if I am wrong.

You can do it. Your URL must look like choose_project/yourAction

@Baloche is right - I've overlooked that since I'm using custom routes for controllers and hadn't such issue before (only with action names).

@Baloche Sorry I didn't understand. Are you saying I should use underscores instead of camel case in controller names, i.e. each upper case is preceded by an underscore.

@amsharma9 Nope.

By default, Phalcon is translating URL adress www.example.com/choose_project/yourAction to a controller named ChooseProjectController and its method yourActionAction (if I'm recalling action name mapping correctly). This controller supposed to be in ChooseProjectController.php. So if you access www.example.com/chooseproject/yourAction' Phalcon will search forChooseprojectControllerinChooseprojectController.php`.

If you would like to have different URLs you can use custom routes for that.

That's right @jodator . @amsharma9 , take a look to phalcon vokuro example (https://github.com/phalcon/vokuro). In the app/controllers folder, you have a controller named UserControlController.php. This controller is called from a custom route (see it in app/config/routes.php)

The same thing happened to me. But not with every every name controller.
For example: both controller and file name TvGuideFeed (camelcase). And the response was something like: "could't find Tvguidefeed" (not camelcase).
The same thing happened to a Tasks Name of a command line application.
As soon as I changed the name TvGuideFeed for Feed the problem was solved.
The funny thing is that I get no error in the development environment (ubuntu -vagrant) I get the error in the integration environment (ubuntu - same configuration as development).

Guys, how is this not a bug? If the first character is uppercase, the rest can't just be bulldozed into lower case. Either you use camel case or you use some other standard. Forcing single-word controller names is just weird and counter intuitive. Naming convention is a big deal. Also, adding routes manually sounds very much like a workaround to me, rather than a proper solution. If there's implicit routing, it should use the same naming conventions as the rest of the framework.

Personally, I have a UrlCamelizer plugin that takes hyphened URLs (/choose-project) in accordance with Google's recommendations and converts to camel case for matching with the Controller / Action names. When the Controller name has been set, Phalcon rewrites my rewrites, breaking the URLs. This must be fixed, in my opinion.

Lastly, not to sound negative, I want to say that Phalcon is an AWESOME framework and I love it! Thanks for your hard work, Phalcon Team!

@dimhoLt I totally agree with you. According to me it is a bug. Why should phalcon force controller names. Maybe it aids them in code generation using developer tool so they kept this restriction but it will break anybody's site and it is not intuitive. It will leave developers wondering why their application doesn't work when everything is ok.

I have exact the same issue when I implement a cli application. I need to run the app like
"php cli.php AnalyticsGetSearchRequest". I got error message like: "AnalyticsgetsearchrequestTask handler class cannot be loaded." As your can notice it change the upper case letter to lower case. To make it work I have to change my php file name from AnalyticsGetSearchRequestTask.php to AnalyticsgetsearchrequestTask.php. The class name defined in the file also need to be changed. To me this is a bug. Also I want to mention that the issue is on CentOS but not the MacOS.

@olivezuo The reason why it doesn't occur on MacOS is because it's case insensitive by default, which CentOS is not. I'd like to see this issue reopened from Phalcon, it is definitely a bug.

+1 vote for "this is a bug"

After reading through the entire thread once more, I need to draw more attention to another thing which I just mentioned - if you have a case insensitive operating system, such as MacOS or Windows, you can name your controller for example ChooseProjectController with corresponding filename, and the implicit route /ChooseProject/ActionName will work. This is, of course, because those operating systems don't make any difference between the names ChooseProjectController.php and ChooseprojectController.php - the file will be returned when PHP requests it.

However, when you use a case sensitive OS, such as Ubuntu, CentOS or any Unix-like (except MacOS, as previously mentioned) all routes with more than two uppercase letters (i.e. the very first, and the C in "Controller") will simply crash with an error because ChooseProject != Chooseproject.

Considering that case sensitive operating systems are used on 62 - 82 % of the web servers, this is simply not viable. Phalcon introduces inconsistencies with:

  • Naming convention standards (PSR-0, CamelCase, namespacing etc ...).
  • Their own chosen naming convention standards (PSR-0).
  • Expected framework behavior.

Phalcon should only care about about the "Controller"-part, and it should be the developers' responsibility to make sure the routes match the file name from there on. Correctly named routes / controllers that get killed by the framework must be considered a bug.

@dimhoLt This nothing has to do with PSR-0 or namespacing, the framework always had worked like this and the standard is clear.

Controller name passed by the router is camelized by dispatcher so:

  • controller-project becomes ControllerProject
  • controllerproject becomes Controllerproject
  • Controller-Project becomes ControllerProject

Action names are always passed lowercased to the view.

The framework currently provides ways to change these behaviors if you don't like them but we can't change the default behavior and break many applications just because you want to consider it a bug.

@phalcon We just need to add 2 cases in your example:

  • controller-project becomes ControllerProject
  • controllerproject becomes Controllerproject
  • Controller-Project becomes ControllerProject
  • controllerProject becomes ControllerProject
  • ControllerProject becomes ControllerProject

Maybe I am wrong since I did not check the source code yet, but I see no reason the last 2 cases will break the code for the first 3 cases.

@olivezuo You can try the following:

<?php

$a = array(
        "controller-project",
        "controllerproject",
        "Controller-Project",
        "controllerProject",
        "ControllerProject"
);
foreach ($a as $v) {
        echo $v, ' => ', \Phalcon\Text::camelize($v), PHP_EOL;
}

It outputs:

controller-project => ControllerProject
controllerproject => Controllerproject
Controller-Project => ControllerProject
controllerProject => Controllerproject
ControllerProject => Controllerproject

This how it currently works, you can say, sure let's change the camelize function so it works as we like but again we don't know how many developers already have addressed this behavior by implementing their applications as the framework currently does behave.

@phalcon That means we can not keep the CamelCase on both controller classes and controller php files. In your example, that also break another practice to keep the class name the same as the php file name. In my case for the Cli application, my task class name is AnalyticsGetSearchRequestTask but the file name has to be AnalyticsgetsearchrequestTask.php.

Your example give me an idea to have a workaround to keep class name and file name the same and also follow the CamelCase in the Cli application. The idea is transform the task name from CamelCase to '-' delimited before send it to the console. Then the dispatcher in the console will transform it back to the right CamelCase for the php file. Here is the code in case anyone interest. If there's a better way please let us know. :)

foreach($argv as $k => $arg) {
    if($k == 1) {
        /* Here is a workaround to make sure Phalcon dispatcher translate the task name to correct Camel format.
         * ex: AnalyticGetSearchRequest => Analytics-Get-Search-Request
        */
        preg_match_all('/[A-Z][^A-Z]*/',$arg,$result);
        $task = implode("-", $result[0]);

        $arguments['task'] = $task;
    } elseif($k == 2) {
        $arguments['action'] = $arg;
    } elseif($k >= 3) {
        $arguments['params'][] = $arg;
    }
}
...
$console->handle($arguments);
...

@phalcon Awesome!

What made me consider this a bug was that previously, I was unable to route the URL /choose-project to ChooseProjectController, which you say is implicit using hyphens. When I asked about this on the official forums in July, I was referred to this workaround in the official documentation. It has nothing to do with what _I think_ is a bug; my experience and tests told me that /choose-project becomes ChooseprojectController, i.e. whatever you name your routes, Controllers are only allowed lower-case names, except for the first character and the 'C' in 'Controller'. I see now that this is not the case.

After your post, I started testing again in accordance with what you wrote, and it does work implicitly (/choose-project --> ChooseProjectController), so I just removed my UrlCamelizer based on the instruction from the documentation about camelization above.

If this is something that has changed, I had missed that. If it hasn't changed, I guess I've been struggling with some version of this problem all along.

Anyway, routes with hyphens work implicitly, and is what should be used for multi-word Controller names.

Thanks for your post, Phalcon rocks! <3

@olivezuo If you run php cli.php analytics-get-search-request, it should work without you having to do any personal rewrites.

@dimhoLt Yes you are right but this is not good for the Operation and support team since they need to know the mapping rules between analytics-get-search-request and AnalyticsGetSearchRequest. That's why I prefer that even in the command line itself the task name should be the same as in class and file names.

Thanks

I just found something interesting... It could be useful for all of you.

When I use Routing based on Annotations, paths stored in autogenerated routes contains third parameter 'exact' => true.
Otherwise, when routes were declared using

$router->add('/some/link',"SomeController::someAction")

there was no such parameter 'exact'.
I'm not sure, but I think this parameter says Phalcon to use 'exact' controller name or generate it with first uppercased letter.

UPD: I was wrong... Couple of tests showed me that 'exact' parameter useless.
BUT!
When you use custom routes, there're few interesting facts:

// Declare route using paths array
$router->add('/demo',['controller' => 'DemoCamelCased' , 'action' => 'index']);
// Declare route using paths short string
$router->add('/demo2','DemoCamelCased::sampleCamelCased');

First case:

// go to http://doma.in/demo
DemocamelcasedController handler class cannot be loaded

Second case:

// go to http://doma.in/demo2
Whoa! All works properly!

So, if you want to use CamelCasedClassNames, use custom routes with short path string.

P.S. It's a BUG. Because paths array and paths short string should to give us the same result, I think. But they are not...

it is totally bug.

When we using CamelSomeClassController it will throw 404
your file class Need to be CamesomeclassController to work

I also think its a bug but it seems its hard to convince the Phalcon community. Its hard to fight an argument like below by @phalcon

_This how it currently works, you can say, sure let's change the camelize function so it works as we like but again we don't know how many developers already have addressed this behavior by implementing their applications as the framework currently does behave._

Just because some people have code working the wrong way we don't change the functionality to what should be the correct way. What will happen five years down the line. Won't it be still more difficult? IMHO if we have to correct our mistake, it must be done now. The earlier we get on the right path, the better for all of us.

@phalcon please provide a demonstration on how to use camel cased controller names with Dispather::forward(). I've tried, it doesn't work:

public function indexAction() {
    return $this->dispatcher->forward([
        'controller' => 'CreateSnap',
        'action' => 'show'
    ]);
 }

I get the follow exception:

PhalconException: CreatesnapController handler class cannot be loaded

@UndergroundLabs it shouldn't be camel-cased

public function indexAction() {
    return $this->dispatcher->forward([
        'controller' => 'create-snap',
        'action' => 'show'
    ]);
 }

@andresgutierrez Damn that was a fast reply. I was about to comment that I solved it by using 'create_snap', but I like the hyphenated version better. Thanks :)

The hyphenated version doesn't work for me on OS X using phalcon 2.0.1, only the underscore version works. The same is true for route definitions.

it is totally bug.

same ....

PHP Fatal error: Uncaught exception 'Phalcon\Cli\Dispatcher\Exception' with message 'Chatroom\Modules\Cli\Tasks\WebsocketeventworkerstartTask handler class cannot be loaded' in /data/webroot/www/websocket/app/modules/cli/tasks/WebsocketTask.php:75

file name is 'WebsocketEventWorkerStartTask.php'

how to fix this bug

https://github.com/phalcon/cphalcon/issues/2572#issuecomment-65152912 It's not a bug actually, it's expected behavior unfortunately which i don't like too.

interesting, development machine is work fine, product machine not work, 很奇怪的命名方式

Because windows is not case sensitive, linux is.

@Jurigag en... development on centos 6.7 , production same

Then idk, somehow your dev machine is not case sensitive or you are lying about file name.

What about your class name?

I use temporary solve
someControllerName -> some-controller-name
SomeControllerName -> some-controller-name

$eventsManager = new EventsManager();
$eventsManager->attach(
    "dispatch:beforeDispatchLoop",
    function (\Phalcon\Events\Event $event, $dispatcher) {
        $ctrlName = $dispatcher->getControllerName();
        $normalizedName = strtolower(preg_replace('/(?<!^)([A-Z])/', '-\1' ,$ctrlName));
        $dispatcher->setControllerName($normalizedName);
    }
);
$dispatcher->setEventsManager($eventsManager);

it is a bug....

@guihouchang Open a new issue then :)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

linxlad picture linxlad  ·  3Comments

kkstun picture kkstun  ·  3Comments

bestirani2 picture bestirani2  ·  3Comments

ismail0234 picture ismail0234  ·  3Comments

mynameisbogdan picture mynameisbogdan  ·  3Comments