-
Notifications
You must be signed in to change notification settings - Fork 7
Tutorial Custom Manager Page
In this tutorial, we'll use Repoman to create a MODX Extra that adds a custom menu page to the MODX manager.
Before we dive in, be aware that MODX manager controllers are not as flexible or intuitive as many of us would like. They are much improved in MODX 2.3, but it's still a bit of a rough ride for new and experienced developers alike.
The other stumbling block is ExtJS: it's not required that you use ExtJS, but the core classes that we'll be extending here are designed more-or-less expecting ExtJS to be used. Repoman doesn't care one way or another, but the learning curve and lack of transparency in ExtJS make it difficult for many users and this page does not demonstrate its use. For simplicity straight-up PHP is demonstrated instead.
To build a CMP in MODX, we need only 3 things:
- An Action Object
- A Menu Object (which references the action)
- A controller (a PHP class that responds to the manager request)
Repoman handles the action and menu objects as seed data; the controller class is where we encounter some friction with the MODX conventions, but we've outlined a workflow for you below.
You can define your action object for your Repoman package as [Seed-Data]. By default, this means you will create the following file: model/seeds/modAction.php
<?php
return array (
'namespace' => 'yournamespace',
'controller' => 'index',
'haslayout' => 1,
'lang_topics' => 'yournamespace:default',
'assets' => '',
'help_url' => '',
);
?>
Note that the "namespace" here is the MODX namespace (NOT a PHP namespace). The index controller is also customizeable.
The menu object for your Repoman package is also defined as [Seed-Data]. By default, this means you will create the following file: model/seeds/modMenu.php
<?php
return array(
array(
'text' => 'My Text', // can be lexicon key
'description' => 'My description', // can be lexicon key
'parent' => 'components',
'action' => 'index',
'icon' => '',
'menuindex' => 0,
'params' => '',
'handler' => '',
'permissions' => '',
'namespace' => 'modxbackup'
),
);
?>
The "text" and "description" items can be lexicon keys.
The link between the menu and the action is defined by the menu's action and namespace parameters. It used to be handled by a foreign key, but this way makes it a bit easier to insert and update data because there's no possibility of errors due to missing keys.
Now that you have an action and a menu item where that action can be called, the last thing you need is a controller class that will handle the request when that action is called. The name and location of the file and class is unfortunately not very flexible: it's a hard-coded convention inside the MODX code. But here's the file we need to create: controllers/default/index.class.php
Inside the index.class.php
must be a class name that follows the pattern {Namespace}{Action}ManagerController
.
For example, if the MODX namespace for your package is "mynamespace" and your action is "index", your classname should be MynamespaceIndexManagerController
. If you use an action other than "index", your filename should be changed as well. Just remember the following:
- Your file name should be lowercase.
- PHP classnames are NOT case-sensitive, but don't get sloppy: use camel casing here.
Your file should contain something like this:
<?php
// Uncomment the "require" line if you are using composer.
// We Gotta do this here because we don't have a reliable event for this.
// require_once dirname(dirname(dirname(__FILE__))) . '/vendor/autoload.php';
class MynamespaceIndexManagerController extends \modExtraManagerController {
/**
* Do any page-specific logic and/or processing here
* @param array $scriptProperties
* @return void
*/
public function process(array $scriptProperties = array())
{
return 'Hello!';
}
}
?>
If you are using Composer, then you can uncomment the line that includes your autoload.php. The process
function is what handles returning output. If all goes well here, you should be able to run php repoman install path/to/your/package
, then clear the cache in the MODX manager and you should see a new menu item under "Extras", and when you click it, you should see the output from your process
function.
Resist the temptation to add namespaces! If you are being a good PHP developer, you may want to use PHP namespaces on all your class files, but this is one place where you must follow the MODX convention, otherwise MODX won't be able to find the class. Later we'll show you how to transition to namespaced controllers via some elementary routing.
You have now created a "primary controller". The file is a PHP class, and it may be the only controller file that you need (e.g. for an "about" page), but frequently this file simply hands off to another PHP class inside of your package's controllers/
directory.
When you are writing a lot of AJAX calls, you may need to reference the URL of a controller in your Javascript code. Thankfully, MODX publishes a list of actions.
CMP Urls:
// Javascript: use this URL where needed
alert(MODx.action['namespace:controller']);
The $scriptProperties array passed to the process() method includes the $_GET and $_POST arrays. You can test this by returning the contents of the array:
public function process(array $scriptProperties = array()) {
return '<pre>'.print_r($scriptProperties, true).'</pre>';
}
© 2014 and beyond by Craftsman Coding