This note began as a short forum post, now expanded and refined for posterity.

Concrete CMS makes extensive use of PHP namespaces to organize its classes. At a high level, a package is simply a directory with a structured set of sub‑directories. Within that structure, developers need to establish a clear mapping between directories, files, namespaces, and the classes they contain.

Concrete CMS provides specific conventions for certain components such as blocks, controllers, and attributes. These conventions ensure consistency across the ecosystem and make it easier for the core framework to locate and load the relevant classes.

For more general classes, however, developers have considerably more flexibility. By convention, reusable or broadly applicable classes are placed under the /src/ sub‑directory. This is a widely adopted practice, but it is not a strict requirement - Concrete CMS will happily load classes from other locations as long as the namespace and auto-loading rules are respected.

General class mapping

The simplest way to do this is to map folders and namespaces is the array $pkgAutoloaderRegistries declared in the package controller. Here we declare that and classes within the namespace \TestClasses can be found beneath the package directory src/TestClasses.

protected $pkgAutoloaderRegistries = ['src/TestClasses' => '\TestClassses']; 

This is not limited to a single mapping. The array is a list of mappings. If some logic is needed in working out what the mapping should be, such as conditionally adding a namespace, we can alternatively declare the method getPackageAutoloaderRegistries() in our package controller.


public function getPackageAutoloaderRegistries()
{
    $namespace_mapping_array = ['src/TestClasses' => '\TestClassses'];
    return $namespace_mapping_array;
}

Within the package, we now have the folder my_package/src/TestClasses/ and within that a file my_package/src/TestClasses/MyTestClass.php. In the file we have:

Namespace TestClassses; 

class MyTestClass {
...
} 

Anywhere we want to use that class we add the line

use TestClassses\MyTestClass;

The namespace \TestClasses applies to the directory src/TestClasses and all classes and directories below that without further mapping. So namespace \TestClasses\WithinNamepace maps to the directory src/TestClasses/WithinNamespace.

Core Conventions

As noted previously, there are Concrete CMS conventions that have to be adhered to for the controllers, blocks, attributes.

Directory / File Namespace / Class
/my_package/controller.php Concrete\Package\MyPackage\Controller
/my_package/blocks/my_block/controller.php Concrete\Package\MyPackage\Block\MyBlock\Controller
/my_package/attributes/my_attribute/controller.php Concrete\Package\MyPackage\Attribute\MyAttribute\Controller
/my_package/controllers/single_page/my_page.php Concrete\Package\MyPackage\Controller\SinglePage\MyPage
/my_package/single_pages/dashboard/my_dash_page.php Concrete\Package\MyPackage\Controller\SinglePage\Dashboard\MyDashPage
/my_package/single_pages/dashboard/my_dash_page.php (dashboard single page view file)

Note the singular/plural and snake_case/CamelCase differences. When the loading of a controller goes wrong, it is often a typo in case or a singular/plural that is the root of the problem.

Vendor Classes

Vendor code is usually located beneath the /vendor/ directory. The php composer will generate an autoloader that needs to be included or required from the package controller on_start() method.

However, we can also use the concrete loader for vendor classes by simply adding an appropriate mapping for the respective /vendor/ sub-directory to $pkgAutoloaderRegistries.

Topics and Tags
Discussion

If you would like to discuss any of these thoughts, please start or continue a thread on the Concrete CMS Forums.