Adding Custom Code Libraries in a Package

Improvements?

Let us know by posting here.

Packages will often need to include custom PHP code for some of their functionality. For example, when adding our custom event to the on_start() method, it will be smarter for us to include this functionality in a separate custom script, rather than directly in the on_start() method. So instead of this:

public function on_start()
{
    \Events::addListener(
        'on_page_view',
        function ($e) {
            $c = $e->getPageObject();
           // do something with the current page object
        });
    );
}

Let's do this:

public function on_start()
{
    $listener = new \Concrete\Package\Statistics\Src\Page\PageListener();
    $listener->addListeners();
}

Let's look at this class. Anything preceded with \Concrete\Package\PackageHandle\Src will automatically map to packages/package_handle/src/. From this point forward, everything within the src/ directory must exactly match the class casing. So our class would be located here: packages/statistics/src/Page/PageListener.php and its namespace would be Concrete\Package\Statistics\Src. This is the automatic namespace for any custom code found inside a package's src/ directory.

Removing \Src from Package and Application Class Files

In early versions of 5.7 we automatically mapped everything inside of Concrete\Package\YourPackage and Application\ that wasn't already covered by an autoloader mapping into the src/ directory. This led to attractive class names like this

Concrete\Package\MyPackage\ServiceProvider\Providepackages/my_package/src/ServiceProvider/Provider.php

Unfortunately, this led to ambiguities. For example, if someone creates a file at packages/my_package/src/Block/Updater.php and references it using \Concrete\Package\MyPackage\Block\Updater – we don't know whether to load from src/ or from the blocks/ directory found inside my_package. For this reason, we've added \Src\ to the namespace of all files loaded from a package's src/ directory or an application's src/ directory.

This isn't ideal; it's ugly and semantically unnecessary. It communicates more about Concrete CMS's implementation of autoloading than an application really should. With that in mind, we've introduced some configuration options for packages and custom code to eliminate this segment.

Fortunately, 5.7.4 makes it easy to ignore this and work around it in a couple different ways.

Registering Custom Autoloaders

First, you can easily register custom autoloaders to points within the src/ directory. Let's say instead of Concrete\Package\Statistics\Src\Page\PageChecker we wanted to map this to MyVendor\ConcreteStatistics\Page\PageChecker. We'd just add this to our controller.php

protected $pkgAutoloaderRegistries = array(
    'src/MyVendor/Statistics' => '\MyVendor\ConcreteStatistics'
);

Now, anything found inside src/MyVendor/Statistics/ will begin its namespace with MyVendor\ConcreteStatistics. So our page checker's class would be

namespace MyVendor\ConcreteStatistics\Page;
class PageChecker
{
}

And the file system would look like: packages/statistics/src/MyVendor/Statistics/Page/PageChecker.php

and out on_start() method would look like this:

public function on_start()
{
    $listener = new \MyVendor\Statistics\Page\PageListener();
    $listener->addListeners();
}

Removing \Src from Concrete\Package namespace.

The above example works well for custom code, but what about the Concrete\Package namespace? This namespace is automatically generated for many things. For example, if you want to include a custom Captcha library in your package, you'll normally need to make sure a file is present at packages/your_package/src/Captcha/YourCustomCaptchaController.php and its class is automatically generated as Concrete\Package\YourPackage\Src\Captcha\YourCustomCaptchaController.

Fortunately, you can remove \Src from this namespace as well. Just add this boolean to your package's controller.php:

$pkgAutoloaderMapCoreExtensions = true;

and make sure that you move any auto-mapped src/ files from within packages/your_package/src/ into packages/your_package/src/Concrete.

From there on, all files found in src/ in your package no longer need to have \Src in their namespace. Your custom captcha controller's class would be

namespace Concrete\Package\YourPackage\Captcha;
class YourCustomCaptchaController
{
}

And the file system would look like: packages/your_package/src/Concrete/Captcha/YourCustomCaptchaController.php.

Intermingling Approaches

These autoloading approaches are complimentary. You can define multiple custom autoloaders as well as the autoloader core extension map boolean. Everything maps to within the src/ directory.