Helix Core is now P4 and Helix Swarm is now P4 Code Review. Learn more >>

Documentation | 2025.2

# Module overview

The operation and testing of custom modules is the responsibility of the module creator. Perforce Software, Inc. is not responsible for the operation of your custom modules, nor does Perforce Software, Inc. make any representations or warranties regarding the interoperability of your custom modules with P4 Code Review.

You must test your custom modules on a test system before transferring them to your production system. This avoids any negative impact on the operation of your production system. If you have more than one custom module, the modules should all be tested at the same time on the same test system as this ensures that the modules operate correctly with each other and with P4 Code Review.

If you add or edit a module, P4 Code Review will not use that change until the config cache has been reloaded, this forces P4 Code Review to use the module change. You must be an admin or super user to reload the P4 Code Review config cache. Navigate to the User id dropdown menu, select System Information, click the Cache Info tab, and click the Reload Configuration button.

A P4 Code Review custom module is created in a folder in the modules folder of your P4 Code Review installation. The folder name must match the custom module name and must contain at least a Module.php file and a module.config.php file. A custom module will not work in P4 Code Review until you enable it. Enable your custom modules in P4 Code Review by adding them to the custom.modules.config.php file in the config directory (a peer of the modules directory).

This chapter provides basic information about how custom modules integrate with P4 Code Review and assumes a basic knowledge of the Laminas framework. For more information about the Laminas framework, see Laminas Quick Start documentation.

This section includes:

- Migrate existing custom modules to the Laminas framework
- Influence activity events, emails, etc.
- Templates
- Custom module file locations
- IndexControllers
- View helpers
- Event listeners
- Enabling your custom modules
- Further reading , includes links to example custom modules and the official Laminas documentation

## Migrate existing custom modules to the Laminas framework

P4 Code Review 2020.1 and later uses the Laminas framework, previous P4 Code Review versions used the Zend framework. The move to Laminas is part of our commitment to move away from using versions of platforms that have reached End-of-Life (EOL).

If you have any custom P4 Code Review modules that were created for P4 Code Review 2019.3 or earlier, you must modify them so that they will work in P4 Code Review 2020.1 and later. The modifications required depend on the version of P4 Code Review you were using the custom modules with before your upgraded P4 Code Review:

- Custom modules on P4 Code Review 2019.1, 2019.2, or 2019.3
- Custom modules on P4 Code Review 2018.3 and earlier

### Custom modules on P4 Code Review 2019.1, 2019.2, or 2019.3

Migrate your custom modules on a test system before transferring them to your production system. This avoids any negative impact on the operation of your production system. If you have more than one custom module, the modules should all be tested at the same time on the same test system as this ensures that the modules operate correctly with each other and with P4 Code Review.

Custom modules used with P4 Code Review 2019.1, 2019.2, and 2019.3 use the Zend 3 framework, they must be migrated to the Laminas framework before they can be used with P4 Code Review 2020.1 and later:

1. Migrate your Zend 3 custom modules to the Laminas framework by pointing the Laminas migration tool at the folder you store your custom modules in. For the migration tool and full instructions on migrating your custom Zend 3 modules to Laminas, see Migration to Laminas.
2. P4 Code Review will not use the custom modules until the P4 Code Review config cache has been deleted. For instructions on deleting the config cache, see P4 Code Review config cache file delete.
3. Check that your custom modules work as expected before putting them on your production system.

### Custom modules on P4 Code Review 2018.3 and earlier

Update and migrate your custom modules on a test system before transferring them to your production system. This avoids any negative impact on the operation of your production system. If you have more than one custom module, the modules should all be tested at the same time on the same test system as this ensures that the modules operate correctly with each other and with P4 Code Review.

Custom modules used with P4 Code Review 2018.3 and earlier use the Zend 2 framework, they must be migrated to the Laminas framework before they can be used with P4 Code Review 2020.1 and later:

1. Convert your Zend 2 custom modules to the Zend 3 framework, see Upgrade custom modules to work with Zend 3.

Laminas is based on the Zend 3 framework, this makes it is relatively simple to convert your Zend 3 custom modules to the Laminas framework:

- If you only have one or two custom modules, you can manually change all of the Zend references in your modules to Laminas while you are converting them from Zend 2. This means you can skip the Laminas migration step.
- If you have a larger number of custom modules, it is probably quicker to automatically change all of the references in your custom modules by running the Laminas migration tool as described in the next step.

2. Migrate your Zend 3 custom modules to the Laminas framework by pointing the Laminas migration tool at the folder you store your custom modules in. For the migration tool and full instructions on migrating your custom Zend 3 modules to Laminas, see Migration to Laminas.
3. P4 Code Review will not use the custom modules until the P4 Code Review config cache has been deleted. For instructions on deleting the config cache, see P4 Code Review config cache file delete.
4. Check that your custom modules work as expected before putting them on your production system.

## Influence activity events, emails, etc.

When something happens in P4 Server (change submitted, files shelved, job added/edited), or state changes within P4 Code Review (comment added, review state changed, etc.), the event is pushed onto the P4 Code Review task queue. A background worker process pulls events off of the queue and publishes an event alerting modules about activity they may be interested in processing. This architecture allows the P4 Code Review user interface to be fairly quick while accommodating tasks that might require notable processing time, or need to wait for related information to become available.

Subscribers to the worker event flesh the item out (fetch the change/job details, for example) and indicate if it should result in an activity entry, email notification, etc. By subscribing to various event topics, your custom module can pay attention to specific types of events. While your custom module is processing an event, it can modify the text of activity events, change the contents of emails, drop things entirely from activity, etc.

When your custom module subscribes to an event, set the priority to influence how early or late in the process it runs. You will likely want your module to run after most other modules have done their work to flesh out the event, but before P4 Code Review's events module processes it. The events module is a good example of subscribing to these events:

swarm_install/module/Events/config/module.config.php

Note that its priority is set to -100. Select a value before that for your own module (for example, 0 would be neutral and -90 would indicate that you are interested in being last).

Event priority is from the highest positive number to the lowest negative number with 0 in the middle. For a full list of tasks and their event priorities, see Task details.

### Task types

For details of each of the following tasks, see Task details.

- task.commit
- task.shelve
- task.review
- task.change
- task.mail

- task.cache.integrity

- task.cleanup.attachment

- task.attachment.thumbnail

- task.cleanup.archive
- task.shelvedel
- task.changesave
- task.changesaved
- task.comment
- task.comment.batch
- task.commentSendDelay
- task.group
- task.groupdel
- task.job

- task.ping

- task.project.created

- task.project.updated

- task.project.updated

- task.testdefinition.migration

- task.testdefinition.updated

- task.testdefinition.created

- task.testdefinition.deleted

- task.testrun

- task.testrun.onDemand.started

- task.testrun.upgrade

- task.user
- task.userdel
- task.workflow.created
- task.workflow.updated

- task.workflow.deleted

- task.workflow.upgrade

## Templates

Override existing view templates using your custom module. Have a look at this example module that demonstrates how to customize the email templates P4 Code Review uses for comment notifications.

For more information about views, see the Laminas-View Quick Start.

P4 Code Review supports the Laminas component versions in the LICENSE.txt file, features and functions in the Laminas documentation that were introduced in later versions of Laminas will not work with P4 Code Review. The LICENSE.txt file is in the readme folder of your P4 Code Review installation.

## Custom module file locations

The custom module files must be stored using the PSR-4 standard locations shown below:

    config/
          custom.modules.config.php (required)
    module/
          ModuleName/ (required)
                    config/ (required)
                          module.config.php (required)
                    src/ (php files here, required)
                       Controller/
                                 MyIndexController.php
                       Listener/ (optional)
                               MyListener.php (optional)
                       ...
                       other directories (non-php files here, optional)
                       ...
                    Module.php (required)

## IndexControllers

Create your IndexControllers using factories. The IndexControllers should extend Application\Controller\AbstractIndexController and use the P4 Code Review IndexControllerFactory, this means that the IndexControllerFactory can automatically inject the services .

We recommend you follow the ::class description to avoid errors in string representation.

    'controllers' => array(
        'factories' => [
            MyModuleName\Controller\IndexController::class => Application\Controller\IndexControllerFactory::class,
        ],
    ),

## View helpers

Create your view helpers using factories. The factories that create the view helpers must inject any services that are required.

We recommend using ::class rather than arbitrary strings as this can limit the possibility of errors. The use of classes also makes your factory simpler because reflection can be used to construct the helpers if they all extend a common parent class.

    'view_helpers' => array(
            'factories' => array_fill_keys(
                [
                    MyModuleName\View\Helper\Helper1::class,
                    MyModuleName\View\Helper\Helper2::class,
                ],
                <YourHelperFactory>::class
            )
        )

### Set options on existing helpers

It is possible to influence the behavior of existing view helpers by setting options on them; for an example see: `swarm_install/module/Application/Module.php`.

### Register new helpers

It is also possible to register new view helpers by placing them within your module's hierarchy, for example, `MyModule/src/View/Helper/Foo.php`. Use the following P4 Code Review view helper for inspiration: `swarm_install/module/Activity/src/View/Helper/Activity.php`.

Then register your view helper with the view manager via your ModuleConfig: `swarm_root/module/Activity/config/module.config.php`.

## Event listeners

Your event listeners should extend Events\Listener\AbstractEventListener. This means that the ListenerFactory can create them without you having to write your own factory.

The Listener.php file contains the implementation of your event listener and the module.config.php file configures your event listeners.

- Look at the code in the AbstractEventListener.php file in module/events/src/Listener to see the functions that are available to you.
- We strongly recommend that you create your event listeners to use the declarative model because it has a number of advantages over the non-declarative model:
  - AbstractEventListener provides common code for listeners to use
  - The declarative model offers better debug options (logging)
  - The declarative model is neater, easier to read, easier to support, and easier to maintain

Example module.config.php file that uses the declarative model for event listeners:

Listener::class example details:

- Events\Listener\ListenerFactory::ALL => [

We are listening to ALL here for convenience because we are listening for mail events but this means it will trigger on every event. Usually is better to just listen for the events you are interested in. For example, if you are interested in commits and shelves you would listen on COMMIT and SHELVE events.

- Events\Listener\ListenerFactory::PRIORITY => -199,

Declares an event priority of -199 for the event listener because email delivery events are processed with a priority of -200 and the example event needs to run just before the email delivery event.

- Events\Listener\ListenerFactory::CALLBACK => 'handleEmail',

Declares the function name within the listener class that is called.

- Events\Listener\ListenerFactory::MANAGER_CONTEXT => 'queue'

Triggers your custom listener when P4 Code Review processes the P4 Code Review event queue.

    <?php
    /**
     * Perforce Swarm
     *
     * @copyright   2019 Perforce Software. All rights reserved.
     * @license     Please see LICENSE.txt in top-level folder of this distribution.
     * @version     <release>/<patch>
    */

    $listeners = [EmailExample\Listener\Listener::class];
    return [
        'listeners' => $listeners,
        'service_manager' =>[
            'factories' => array_fill_keys(
                $listeners,
                Events\Listener\ListenerFactory::class
            )
        ],
        Events\Listener\ListenerFactory::EVENT_LISTENER_CONFIG => [
            Events\Listener\ListenerFactory::ALL => [
                EmailExample\Listener\Listener::class => [
                    [
                        Events\Listener\ListenerFactory::PRIORITY => -199,
                        Events\Listener\ListenerFactory::CALLBACK => 'handleEmail',
                        Events\Listener\ListenerFactory::MANAGER_CONTEXT => 'queue'
                    ]
                ]
            ]
        ]
    ];

Example of an email Listener.php file:

    namespace MyModuleName\Listener;

    use Events\Listener\AbstractEventListener;
    use Laminas\EventManager\Event;

    class Listener extends AbstractEventListener
    {
        public function handleEmail(Event $event)
        {
            $mail = $event->getParam('mail');
            if (!$mail || !isset($mail['htmlTemplate'], $mail['textTemplate'])) {
                return;
            }
        }
    }

## Enabling your custom modules

P4 Code Review uses the custom.modules.config.php file to check which custom modules it should load. This gives you control over which modules P4 Code Review loads and prevents modules from being loaded by mistake.

Create the custom.modules.config.php file in the `config` directory (a peer of the modules directory) if it does not already exist. Edit the file so that it contains the following details for each of your modules:

- namespaces array: enter your custom module names and paths
- return array : enter your custom module names

For example, if you have three modules called MyModuleName, AnotherModuleName, and NewModuleName the file content would look similar to:

    <?php
    \Laminas\Loader\AutoloaderFactory::factory(
        array(
            'Laminas\Loader\StandardAutoloader' => array(
                'namespaces' => array(
                    'MyModuleName'       => BASE_PATH . '/module/MyModuleName/src',
                    'AnotherModuleName'  => BASE_PATH . '/module/AnotherModuleName/src',
                    'NewModuleName'      => BASE_PATH . '/module/NewModuleName/src',
                )
            )
        )
    );
    return [
        'MyModuleName',
        'AnotherModuleName',
        'NewModuleName',
    ];

## Further reading

For detailed information about the Laminas framework and examples see the following:

- The Laminas Quick Start documentation and Laminas framework documentation portal, it is useful to have a basic knowledge of the Laminas framework before you create your own modules. .

P4 Code Review supports the Laminas component versions in the LICENSE.txt file, features and functions in the Laminas documentation that were introduced in later versions of Laminas will not work with P4 Code Review. The LICENSE.txt file is in the readme folder of your P4 Code Review installation.

- Example email module, a simple custom module that makes P4 Code Review use a custom email template when it sends out when a comment notification is sent out.
- P4 Code Review JIRA module, a simple module implementation within P4 Code Review: swarm_install/module/Jira

Your search for returned results