SkillAgentSearch skills...

ZoomX

Alternative way to use PHP template engines instead of the MODX template engine.

Install / Use

/learn @sergant210/ZoomX
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

(Documentation in the process of creation).

ZoomX offers an alternative way to handling a request and preparing a response. The main goal is not to use elements from the database (as far as it's possible) and use your favorite IDE and versioning support for convinient development. The modRequest class has been refactored and optimized. In addition, a routing mechanism is built in. FastRoute is used for this. Usual DB templates will be used only if the "zoomx_use_zoomx_parser_as_default" system setting is true. Otherwise, they will be ignored and will only be used to bind TVs to resources. When preparing a response, the standard parser is not used (in the strict router mode). PHP template engines are used instead. Smarty template engine comes out of the box. Because it's installed along with MODX.

IMPORTANT

It's required PHP >= 7.1.


How to use

Install this package over the Package Manager. Switch On the system setting "friendly_urls". After that open core/config/routes.php and uncomment the required routes or define your own. Initially, templates are located in the folder core /components/zoomx/templates/default/. But it can be redefined. Two system settings are responsible for this - zoomx_template_dir (by default, core/components/zoomx/templates/) and zoomx_theme (by default, default). I advise to move the template folder to core/templates/. Otherwise, all changes will be lost on next updates.

There are 3 templates out of the box - "base.tpl", "index.tpl" and "error.tpl". Create your own templates and chunks (partials or subtemplates) using them as template.

Error templates

By default, the error.tpl template is used for all errors. If you need your own template for a specific error, create a template with a name in the form of an error code. For example, the template for error 404 should be called '404.tpl'.

Routing

Creating routes

Next, you need to associate the created templates with resources. To do this, open the file core/config/routes.php and add a route for the corresponding URI.

$router->get('hello.html', function() {
    return new ZoomView('hello.tpl', ['name' => 'John']);
});
$router->get('users/{id}', function($id) use($modx) {
    $user = $modx->getObject('modUser', ['id' => (int)$id]);
    return viewx('profile.tpl', $user ? $user->toArray() : []);
});

Read more about routes in the documentation for FastRoute.

You can return a string.

$router->get('hello.html', function() {
    return '<h1>Hello, John!</h1>';
});

Example of redirecting

// Using the modX::sendRedirect method.
$router->get('product1.html', function() use($modx) {
    $modx->sendRedirect('catalog/product2.html');
});
// Using the resource identifier.
$router->get('resource.html', function() use($modx) {
    // Specify resource id
    $modx->resourceIdentifier = 2;  
    // Or resource URI
    $modx->resourceIdentifier = 'another.html';
    
    return viewx('page.tpl');
});
// Using short redirect format $router->redirect($fromUri, $toUri, $statusCode);
 $router->redirect('resource{id}.html', 'resource{$id}', 301);  // redirects from 'article1.html' to 'article1'

Controllers

You can use controllers instead of functions. Routes that used controllers can be cached. This has a positive effect on productivity. The system setting zoomx_cache_routes is responsible for caching routes.

$router->get('users', ['Zoomx\Controllers\UserController', 'index']);
// The index method can be omitted
$router->get('users', Zoomx\Controllers\UserController::class);

For brevity, controllers can be specified without a namespace. The namespace specified in the system setting zoomx_contoller_namespace will be added automatically.

$router->get('users/{id}', ['UserController', 'show']); // Zoomx\Controllers\UserController::show() will be called. 

If you specify a slash before the controller name, the namespace will not be added.

$router->get('users/{id}', ['\UserController', 'show']); // UserController::show() will be called. 
$router->get('users/{id}', ['\Custom\Namespace\UserController', 'show']); // Custom\Namespace\UserController::show() will be called. 

Controllers must extend the base controller Zoomx\Controllers\Controller.

<?php

namespace Zoomx\Controllers;

class UserController extends Controller
{
    public function index()
    {
        return viewx('users.tpl');
    }
}

Routing mode

The router can work in 3 modes:

  • Disabled. All specified routes are ignored. MODX will work as usual.
  • Soft (mixed). If no route is found for the request URI, MODX will continue processing the request as usual. If the route was found and the resource was not found, the 404 error will be fired as in Strict mode.
  • Strict (exclusive). If no route is found for the request URI, 404 error will occur and processing of the request will be stopped.

Virtual pages

By default, MODX searches for a resource for the URI specified in the route. But if you want to define the resource yourself, for example for RESTful mode, then disable the resource autoloading in the zoomx_autoload_resource system setting. If you need to disable the resource autoloading only in a particular route, you can change the setting directly in the route.

$router->get('users/{id}/profile',  function ($id) use ($modx) {
    zoomx()->autoloadResource(false);  // === $modx->setOption('zoomx_autoload_resource', false); 
    $user = $modx->getObject('modUser', ['id' => (int)$id])
    if (!user) {
        abortx(404, 'User not found');
    } 
    return viewx('profile.tpl', ['user' => $user]);
});

Working in API mode

Now you don't need to create a particular controller for API requests. Just define a corresponding route. From the frontend you have to pass the header "Accept" with "application/json" value in the request. In this case, MODX will not search for the resource by URI and will return only the specified data.

Return an array and you get back a json encoding response.

// Return an array
$router->get('api/foo', function() {
    return ['foo' => 'bar']);
});
// Or a JSON Response with custom headers.
$router->get('api', function() {
    return jsonx(['foo' => 'bar'], ['Foo' => 'Bar']);
});

The response will be converted to json format

{
  success: true,
  data: {
      foo: "bar"
  },
  meta: {
  	total_time: "0.0230 s",
  	query_time: "0.0000 s",
  	php_time: "0.0230 s",
  	queries: 1,
  	memory: "2 048 kb"
  }
}

Meta information can be switched off by the system setting zoomx_include_request_info.

Get a resource either from the cache or from the database

$router->get('api/resource/{id}', function($id) {
    $resource = zoomx()->getResource[(int)$id]);
    return jsonx($resource->toArray());
});

To return a failure response use the abortx function with corresponding HTTP code

$router->get('profile', function() use($modx) {
    if (!$modx->user->isAuthenticated()) {
        abortx(401, 'You must log in.');
    } 
return jsonx($modx->user->Profile->toArray());
});

Smarty template engine

Smarty is a fast and powerful template engine and it comes out of the box. Besides, it has many predefined plugins (built-in functions, custom functions, [built-in modifiers](https://www.smarty.net/docs/en/language.modifiers.tpl. You can find all the default modifiers in the Smarty documentation. ZoomX adds its own plugins.

Using Smarty

By default, Smarty works only when a route for the specified URI is found. In other cases, the parser specified in the parser_class setting works. Using the system setting zoomx_use_zoomx_parser_as_default, you can specify that Smarty is always used as the default template engine. But only the template content will be parsed. The content of the resource will not be processed. Here is an expample of a MODX Template:

<!doctype html>
<html lang="{'cultureKey'|config}">
<head>
    {block "title"}<title>{'pagetitle'|resource} - {'site_name'|config}</title>{/block}
    <base href="{'site_url'|config}" />
    <meta charset="{'modx_charset'|config}" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
    {block "styles"}{/block}
</head>
<body>
    <div class="container">
    {block "content"}
        {'content'|resource}  // to parse the resource content - {'content'|resource|parse}
    {/block}
    </div>
    {block "script
View on GitHub
GitHub Stars27
CategoryDevelopment
Updated10mo ago
Forks3

Languages

PHP

Security Score

67/100

Audited on May 22, 2025

No findings