Moving getControllerConfig to module.config.php

Hi everyone!

I’ve been trying to get rid of the getControllerConfig() Method, and move it over to the Module’s module.config.php.
Sadly, in the progress of doing so, I am encountering this error:

A 404 error occurred
Page not found.

The requested controller could not be mapped to an existing controller class.

Controller:
    Project\Controller\ProjectController (resolves to invalid controller class or alias: Project\Controller\ProjectController) 

No Exception available

My Module.php:

<?php

namespace Project;

use Laminas\ModuleManager\Feature\ConfigProviderInterface;
use Project\Controller\Factory\ProjectControllerFactory;
use Project\Model\Factory\ProjectTableFactory;
use Project\Model\Factory\ProjectTableGatewayFactory;

class Module implements ConfigProviderInterface
{
    public function getConfig()
    {
        return include __DIR__ . '/../config/module.config.php';
    }

    // public function getControllerConfig()
    // {
    //     return [
    //         'factories' => [
    //             Controller\ProjectController::class => ProjectControllerFactory::class
    //         ],
    //     ];
    // }
}

And my module.config.php:

<?php

namespace Project;

use Laminas\Router\Http\Segment;
use Project\Controller\Factory\ProjectControllerFactory;
use Project\Controller\ProjectController;
use Project\Model\Factory\ProjectTableFactory;
use Project\Model\Factory\ProjectTableGatewayFactory;
use Project\Model\ProjectTable;

return [
    'router' => [
        'routes' => [
            'project' => [
                'type'    => Segment::class,
                'options' => [
                    'route' => '/project[/:action[/:id]]',
                    'constraints' => [
                        'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
                        'id'     => '[0-9]+',
                    ],
                    'defaults' => [
                        'controller' => Project\Controller\ProjectController::class,
                        'action'     => 'index',
                    ],
                ],
            ],
        ],
    ],
    'view_manager' => [
        'template_path_stack' => [
            'project' => __DIR__ . '/../view',
        ],
    ],
    'service_manager' => [
        'factories' => [
            ProjectTable::class => ProjectTableFactory::class,
            Model\ProjectTableGateway::class => ProjectTableGatewayFactory::class,
        ]
    ],
    'controller' => [
        'factories' => [
            ProjectController::class => ProjectControllerFactory::class
        ]
    ]
];

Your help would be greatly appreciated.

Also, this post helped me move the getServiceConfig() over. I just missed some import statements.

Hello and welcome to our forums! :smiley:

The usage of namespace and classnames are wrong. You set the namespace to Project and then you use for the controller Project\Controller\ProjectController::class.
The result is: Project\Project\Controller\ProjectController::class

Update this line:

'controller' => Controller\ProjectController::class,

See also the example in the PHP documentation: https://www.php.net/manual/language.namespaces.basics.php

1 Like

Ah, there is also an import for the controller class:

So you can write:

'controller' => ProjectController::class,

See also: Laminas-cli: service_manager config in module.config.php doesn't work - #9 by froschdesign

1 Like

You’re fast, thanks!
That line is under defaults beneath router, right?
Error is still there. (For good measure, I composer dump’ed autoload and restarted the php dev server)
Updated file:

<?php

namespace Project;

use Laminas\Router\Http\Segment;
use Project\Controller\Factory\ProjectControllerFactory;
use Project\Controller\ProjectController;
use Project\Model\Factory\ProjectTableFactory;
use Project\Model\Factory\ProjectTableGatewayFactory;
use Project\Model\ProjectTable;

return [
    'router' => [
        'routes' => [
            'project' => [
                'type'    => Segment::class,
                'options' => [
                    'route' => '/project[/:action[/:id]]',
                    'constraints' => [
                        'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
                        'id'     => '[0-9]+',
                    ],
                    'defaults' => [
                        'controller' => ProjectController::class, //changed this
                        'action'     => 'index',
                    ],
                ],
            ],
        ],
    ],
    'view_manager' => [
        'template_path_stack' => [
            'project' => __DIR__ . '/../view',
        ],
    ],
    'service_manager' => [
        'factories' => [
            ProjectTable::class => ProjectTableFactory::class,
            Model\ProjectTableGateway::class => ProjectTableGatewayFactory::class,
        ]
    ],
    'controller' => [
        'factories' => [
            ProjectController::class => ProjectControllerFactory::class
        ]
    ]
];

The config file looks good now. Please check the Composer configuration and the filenames.

If you use the skeleton application then the Composer configuration should contain:

"autoload": {
    "psr-4": {
        "Application\\": "module/Application/src/",
        "Project\\": "module/Project/src/"
    }
},

And the filenames must be:

  • module/Project/src/Controller/ProjectController.php
  • module/Project/src/Controller/Factory/ProjectControllerFactory.php

Check also the namespace and classname in the files:

namespace Project\Controller;

class ProjectController
namespace Project\Controller\Factory;

class ProjectControllerFactory

The composer config, the paths, the filenames, the namespaces and the class names are looking good so far.
module\Project\src\Controller\ProjectController.php:

<?php

namespace Project\Controller;

use Laminas\Mvc\Controller\AbstractActionController;
use Laminas\View\Model\ViewModel;
use Project\Model\ProjectTable;
use Project\Form\ProjectForm;
use Project\Model\Project;
use Laminas\Json\Encoder;
use InvalidArgumentException;
use Project\Form\UploadForm;
use Project\Form\Validator\DirectoriesCreated;

class ProjectController extends AbstractActionController
{
    private $table;

module\Project\src\Controller\Factory\ProjectControllerFactory.php:

<?php
namespace Project\Controller\Factory;

use Interop\Container\ContainerInterface;
use Laminas\ServiceManager\Factory\FactoryInterface;
use Project\Controller\ProjectController;
use Project\Model\ProjectTable;

class ProjectControllerFactory implements FactoryInterface {
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
    {

This is wrong:

It must be controllers! :see_no_evil:

1 Like

Jackpot lol, thanks again!

Dayum, feeling stupid now.

Please keep in mind that there was also a problem with the namespace.

No, the problem is when a configuration file type is used that does not support a schema.

Some sort of schematic config would indeed be pretty cool. I saw there’s laminas-config, could that be used to get that?

There is already an industry standard for it: XML :smiley:

No, that does not work. The config object uses internal an array as storage and the magic methods for setter and getter. Without special comments it does not help.

There are some attempts to solve this via extensions of IDEs, like:

This works for PHP arrays but at the moment it does not help with schemas from multiple classes or comments.
And in the end, it’s also only a workaround.


I would not make this dependent on a framework or a special tool like an extension, it should be available everywhere.

isn’t json more common? :stuck_out_tongue_winking_eye: :wink:

Wow, these plugin look awesome. I might be giving them a try somewhen.
In the end, you’re right again; there should be some sort of universally available solution. If a language server implemented that, that’d get pretty close to an independent tool. Maybe some folks end up adapting one of the deep assoc plugins for the IDEs.