We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Micro/Medium application can't mount handlers

I'm currently separating my API from a full Phalcon website to a micro/medium one for easier maintenance and devops purposes.

I've separated my api into collections. These collections use the methods from the corresponding controllers. It however seems that Phalcon cannot find the namespace my controllers reside in.

All my controllers are separated into namespaces: Ontrack\Controllers\Api\V1 These controllers extend from a ControllerBase which extends on its own from the Phalcon Controller class.

How can this issue be fixed?

Full error:

There are no handlers to mount
#0 /home/vagrant/workspace/phalcon/api/public/index.php(43): Phalcon\Mvc\Micro->mount(Object(Phalcon\Mvc\Micro\Collection))
#1 {main}

When I change my general-user.php file to use an UserController object I get a different error:


( ! ) Fatal error: Uncaught Error: Class 'Ontrack\Controllers\Api\V1\UserController' not found in /home/vagrant/workspace/phalcon/api/app/collections/v1/general-user.php on line 6
( ! ) Error: Class 'Ontrack\Controllers\Api\V1\UserController' not found in /home/vagrant/workspace/phalcon/api/app/collections/v1/general-user.php on line 6
Call Stack
#   Time    Memory  Function    Location
1   0.0030  361992  {main}( )   .../index.php:0
2   0.0080  377968  include( '/home/vagrant/workspace/phalcon/api/app/config/routes.php' )  .../index.php:40
3   0.0144  379624  include( '/home/vagrant/workspace/phalcon/api/app/collections/v1/general-user.php' )    .../routes.php:5

Folder structure:

- app
--collections
--config
--controllers
---v1
-public

Contents of /public/index.php:

<?php

use Phalcon\Mvc\Micro;
use Phalcon\Di\FactoryDefault;

error_reporting(E_ALL);

define('BASE_PATH', dirname(__DIR__));
define('APP_PATH', BASE_PATH . '/app');

try {

    /**
     * The FactoryDefault Dependency Injector automatically registers
     * the services that provide a full stack framework.
     */
    $di = new FactoryDefault();

    /**
     * Read services
     */
    include APP_PATH . "/config/services.php";

    /**
     * Get config service for use in inline setup below
     */
    $config = $di->getConfig();
    /**
     * Include Autoloader
     */
    include APP_PATH . '/config/loader.php';

    /**
     * Handle and deploy the application
     */
    $application = new Micro();
    $application->setDI($di);

    //Loading all API routes
    include APP_PATH . '/config/routes.php';
    foreach($collections as $collection) {
      $application->mount($collection);
    }

    $application->notFound(function () use ($application) {
      $application->response->setStatusCode(404, "Not Found")->sendHeaders();
      echo "not found!";
    });

    $application->handle();

} catch (\Exception $e) {
    echo $e->getMessage() . '<br>';
    echo '<pre>' . $e->getTraceAsString() . '</pre>';
}

Contents of /app/collections/v1/general-user.php:

<?php
use Phalcon\Mvc\Micro\Collection as MicroCollection;
use Ontrack\Controllers\Api\V1\UserController as UserController;

$general_user = new MicroCollection();
$general_user->setHandler('Ontrack\\Controllers\\Api\\V1\\UserController', true);
$general_user->setPrefix('/v1/user');
$general_user->post('/revokedevice', 'revokedeviceAction');

return $general_user;

Contents of /app/config/config.php:

<?php
defined('BASE_PATH') || define('BASE_PATH', getenv('BASE_PATH') ?: realpath(dirname(__FILE__) . '/../..'));
defined('APP_PATH') || define('APP_PATH', BASE_PATH . '/app');

return new \Phalcon\Config([
    'database' => [
      'adapter'     => 'Mysql',
      'host'        => 'localhost',
      'username'    => 'root',
      'password'    => '',
      'dbname'      => 'defaultname',
      'charset'     => 'utf8',
    ],
    'application' => [
      'applicationname'     => 'MyApp',
      'appDir'              => APP_PATH . '/',
      'controllersDir'      => APP_PATH . '/controllers/',
      'modelsDir'           => APP_PATH . '/models/'

      // This allows the baseUri to be understand project paths that are not in the root directory
      // of the webpspace.  This will break if the public/index.php entry point is moved or
      // possibly if the web server rewrite rules are changed. This can also be set to a static path.
      'baseUri'        => '/',
    ]
]);

Contents of /app/config/loader.php:

<?php

$loader = new \Phalcon\Loader();

/**
 * We're a registering a set of directories taken from the configuration file
 */
$loader->registerDirs(
    [
        $config->application->controllersDir,
        $config->application->modelsDir,
    ]
)->register();

$loader->registerNamespaces(
    [
        //EXAMPLE     "Example\Base"    => "vendor/example/base/",        USAGE     $var = new Example\Base();
        'Ontrack\Controllers\Api' => APP_PATH . '/controllers/v1/',
        'Ontrack\Models' => APP_PATH . '/models/',
        'Ontrack\Vendors' => $config->application->vendorDir,
    ]
)->register();

Contents of /app/config/routes.php:

<?php

$collections = [
  include APP_PATH . '/collections/v1/general-auth.php',
  include APP_PATH . '/collections/v1/general-user.php',
];

return $collections;

Contents of /app/config/services.php:

<?php
/**
 * Shared configuration service
 */
$di->setShared('config', function () {
  return include APP_PATH . "/config/config.php";
});

/**
 * The URL component is used to generate all kind of urls in the application
 */
$di->setShared('url', function () {
    $config = $this->getConfig();

    $url = new UrlResolver();
    $url->setBaseUri($config->application->baseUri);

    return $url;
});

/**
 * Database connection is created based in the parameters defined in the configuration file
 */
$di->setShared('db', function () {
  $config = $this->getConfig();

  $class = 'Phalcon\Db\Adapter\Pdo\\' . $config->database->adapter;
  $params = [
      'host'     => $config->database->host,
      'username' => $config->database->username,
      'password' => $config->database->password,
      'dbname'   => $config->database->dbname,
      'charset'  => $config->database->charset
  ];

  if ($config->database->adapter == 'Postgresql') {
      unset($params['charset']);
  }

  $connection = new $class($params);

  return $connection;
});


77.7k
Accepted
answer

Contents of /app/config/loader.php:

$loader->registerNamespaces(
    [
        'Ontrack\Controllers\Api' => APP_PATH . '/controllers/v1/', // wrong namespace, missing V1
        'Ontrack\Controllers\Api\V1' => APP_PATH . '/controllers/v1/', // correct
        'Ontrack\Models' => APP_PATH . '/models/',
        'Ontrack\Vendors' => $config->application->vendorDir,
    ]
)

This is the only error I've found skmming your code... hope it helps



5.9k

It looks like changing this line did load the namespace/controller correctly. However I still have the same error message: There are no handlers to mount

Changing my general-user.php lines to instantiating an object in setHandler doesn't return class not found anymore so namespace loading is now correct.

Contents of /app/config/loader.php:

$loader->registerNamespaces(
   [
       'Ontrack\Controllers\Api' => APP_PATH . '/controllers/v1/', // wrong namespace, missing V1
       'Ontrack\Controllers\Api\V1' => APP_PATH . '/controllers/v1/', // correct
       'Ontrack\Models' => APP_PATH . '/models/',
       'Ontrack\Vendors' => $config->application->vendorDir,
   ]
)

This is the only error I've found skmming your code... hope it helps



5.9k
edited Aug '17

EDIT: I stupidly used a POST where I simply wanted to test a GET request. So it's fixed now!

I've managed to remove the There are no handlers to mount message by removing some empty and faulty configured collection files from my routes.php file.

My current issue is that it only shows me a not found! message like I declared in index.php.

edited Aug '17

Where is your Router service in services? It's by default set via FactoryDefault DI, but you need to change few bits there (i.e. redefine service).

I can bet that's your issue ATM.

This is what I'm using with Middle / APIs:

$di->setShared('router', function (){
// Phalcon\Mvc\Router has a default behavior that provides a very simple routing that always expects a URI that matches the following pattern: /:controller/:action/:params

        $router = new \Phalcon\Mvc\Router(false); //Create the router without default routes

        //we're using Front Page Controller pattern in relation from nginx -> Phalcon
        $router->setUriSource($router::URI_SOURCE_SERVER_REQUEST_URI); // Use $_SERVER['REQUEST_URI']

        //Set whether router must remove the extra slashes in the handled routes
        $router->removeExtraSlashes(true);

    return $router;
});

And fit your web server accordingly. This is what you need for nginx:

location / {
# FontPageController pattern
            try_files $uri $uri/ /index.php$is_args$query_string;
}