Write your first module view
This task guide is for PHP developers who want a new page at an address of their own. At the end you have an
extension acmereport with a module acmereport and a view list at /acmereport/list, written as a class,
protected by a policy, rendering a template. Replace acme with your own prefix
(Class naming and the exp prefix).
Contents
- Before you start
- Step 1: the extension and its activation
- Step 2: register the module
- Step 3: declare the view and the policy
- Step 4: the view class
- Step 5: the view file
- Step 6: the template
- Step 7: autoloads, caches, a policy
- Step 8: check it
- What to do next
Before you start
You need a development checkout with an installation (Setting up a PHP development checkout) and an administrator account to assign a policy. The files you create:
extension/acmereport/
settings/site.ini.append.php
settings/module.ini.append.php
modules/acmereport/module.php
modules/acmereport/list.php
classes/runnable/views/acmereport/list.php
design/standard/templates/acmereport/list.tplStep 1: the extension and its activation
Create the directory extension/acmereport/ and activate it for the installation in
settings/override/site.ini.append.php:
[ExtensionSettings]
ActiveExtensions[]=acmereportStep 2: register the module
extension/acmereport/settings/module.ini.append.php:
[ModuleSettings]
ExtensionRepositories[]=acmereport
ModuleList[]=acmereport
*/ ?>ExtensionRepositories[] tells the kernel to look for modules in extension/acmereport/modules/.
Step 3: declare the view and the policy
extension/acmereport/modules/acmereport/module.php:
$Module = array( 'name' => 'Acme report' );
$ViewList = array();
$ViewList['list'] = array(
'script' => 'list.php',
'functions' => array( 'read' ),
'params' => array(),
'unordered_params' => array( 'offset' => 'Offset' ) );
$FunctionList = array();
$FunctionList['read'] = array();functionsnames the policy a user needs:acmereport/read.unordered_paramsmaps/acmereport/list/(offset)/20to$Params['Offset'].- Every key is described in module.php reference.
Step 4: the view class
extension/acmereport/classes/runnable/views/acmereport/list.php:
namespace Exponential\View\Extension\Acmereport\Acmereport;
class ListView extends \Exponential\Runnable\ModuleView
{
public function run( array $scope )
{
$params = $scope['Params'];
$offset = isset( $params['Offset'] ) ? max( 0, (int)$params['Offset'] ) : 0;
$items = \eZPersistentObject::fetchObjectList( \acmeReportItem::definition(), null, null,
array( 'created' => 'desc' ),
array( 'offset' => $offset, 'length' => 20 ) );
$tpl = \eZTemplate::factory();
$tpl->setVariable( 'items', is_array( $items ) ? $items : array() );
$tpl->setVariable( 'offset', $offset );
return array(
'content' => $tpl->fetch( 'design:acmereport/list.tpl' ),
'path' => array( array( 'text' => \ezpI18n::tr( 'extension/acmereport', 'Reports' ), 'url' => false ) ) );
}
}list is a reserved word in PHP, so the class is named ListView, as the kernel names its own (Exponential\View\Kernel\Section\ListView); the namespace follows
Exponential\View\Extension\<Ext>\<Module>\<View> (Module views as classes). The
acmeReportItem class is the persistent object of
Persistent object definitions in depth; for a first try, pass an array
instead.
Step 5: the view file
extension/acmereport/modules/acmereport/list.php, the file module.php names, is one line:
return \Exponential\View\Extension\Acmereport\Acmereport\ListView::main( __FILE__, get_defined_vars() );get_defined_vars() hands the class what eZProcess::runFile() defined: $Params (with the module as
$Params['Module']) and the rest.
Step 6: the template
extension/acmereport/design/standard/templates/acmereport/list.tpl:
<h1>{'Reports'|i18n( 'extension/acmereport' )}</h1>
{if $items|count}
<ul>
{foreach $items as $item}
<li>{$item.status|wash}: {$item.amount|wash}</li>
{/foreach}
</ul>
{else}
<p>{'No reports yet.'|i18n( 'extension/acmereport' )}</p>
{/if}Register the design so the template is found, in extension/acmereport/settings/design.ini.append.php:
[ExtensionSettings]
DesignExtensions[]=acmereport
*/ ?>Every value goes through |wash (Escaping output from PHP).
Step 7: autoloads, caches, a policy
php -l extension/acmereport/classes/runnable/views/acmereport/list.php
php bin/php/ezpgenerateautoloads.php -e
php bin/php/ezcache.php --clear-allIn the administration, Roles and policies: give a test role the policy acmereport/read (module acmereport,
function read) and assign the role to your test user. Under Velocity, run php bin/php/console exp:velocity deploy
instead of the cache command, so the workers load the new class.
Step 8: check it
Open /acmereport/list on the site's siteaccess, signed in as the test user.
| You see | Cause |
|---|---|
| the module or view was not found | ModuleList[] or ExtensionRepositories[] missing, or the INI cache not cleared |
| access denied | the user lacks acmereport/read |
Class ... not found | autoloads not regenerated, or the namespace and class name differ from the view file |
| the template was not found | DesignExtensions[] missing, or the path under templates/ differs |
| an empty page | a PHP error: enable the debug output and read var/log/error.log |
What to do next
- Add a form with actions and the form token: Custom modules and views.
- Give templates the data with a fetch function: Write a fetch function.
- Test the logic without a database: PHPUnit without a database.
- Do it faster next time with Setup > RAD (RAD tools).
Related pages
- Modules and views (extension developers)
- View results, templates and the pagelayout
- Policy functions and limitations
- Free documentation: this page is free to copy, translate and improve under the GNU FDL 1.3.
Become an Exponential Partner
Partners share their information, provide funding, contribute back and develop the products with us, and that is how Exponential grows. A partner website and dashboard are planned for mid-2027: please become a partner today to speed up our growth rate and land new features faster.