The paradigm of programming by the processor in MODx Revolution

just specify that this article is speculation and food for thought. Absolutely don't want to arrange holivar and to impose on others their methods of programming. Just telling you as myself feel that I have used programming techniques over the past year changed dramatically and fundamentally different from the methods of previous years.

In this article I would like to tell you how MODx Revolution as a whole changed my approach to programming.
I do not know who is programming, but I believe that a long time ago programming techniques object-oriented programming. What in General terms was the programming? I wrote (or take ready) classes for their tasks (class work with a database class for working with templates, the class still under something). Most of the classes were quite large and perform many necessary tasks on your profile. Most often the growth of the project, many classes grew, or acquire extensions, or both. Anyway, I'm sure many are faced with the situation time of the analysis object in a couple of thousands of rows and dozens of techniques to understand where you can make further changes, but in this case something else broke. But in my opinion the most difficult to ensure harmonious interaction of various objects among themselves, particularly in terms of intercepting errors when performing certain actions, and most importantly at the time of the error to decide if it is critical and whether to interrupt the execution process, or you can go further. And still here to attribute to a client-server solution, to standardize the answers of execution and for the server part (with further rendering in the templates), and for Ajax requests.

What the Toolkit provides MODx Revolution for programming logic of the project? Only two classes: CPU (runs class modProcessor) and the Connector (conducted by class modConnector).
What is it? Processor — a separate file with most often one or several small tasks, the result of which the response should only be positive (which would indicate a positive result of performance) or negative (preferably with specific error message), it would be needless to say that there was something critically wrong.

Give a small example. We want to create a new document. If the document is created, then great, if not, we need to get the error message.

1. Create a folder in our processor core/model/modx/processors/, let's call it, for example, assets/
2. Create a file processor doc/create.php (the full path will work core/model/modx/processors/assets/doc/create.php)
3. Prescribe it we need the code
<?
if(!$scriptProperties['pagetitle']){
return $modx- > error- > failure('did Not specify a title');
}
if(!isset($scriptProperties['parent'])){
return $modx- > error- > failure('did Not specify a parent document');
}

$doc = $modx- > newObject('modResource', scriptProperties);

if(!$doc- > save()){
return $modx- > error- > failure('failed to save document');
}

return $modx->error->success('Document successfully created', $doc->toArray());


4. Now in the right place, we will call this processor
$response = $modx- > runProcessor('assets.doc.create', array(
'parent' => 0,
'pagetitle' => 'Our document'
));

if($response->isError()){
print "an error Occurred". $response->getMessage();
}
else{
$object = $response->getObject();
print "document was created with ID {$object['id']}";
}

/*$modx- > runProcessor - standard method MODx. File extension .php executable is added automatically, so we don't need to write create.php
Point to the folder separator. That is, in this case, assets.doc.the create says that the executable file is
in the folder assets/doc/
By default, the search of the executable file is in the folder core/model/modx/processors/
You can pass a third parameter, the options array, in particular putting his nanka processors
$modx- > runProcessor($path, $properties, array( processors_path => self::$processorsPath));

Also inside the CPU is visible to the object $modx, which frees us from the need to global it in our custom methods.
*/


This particular example reveals not even about what I wanted to say.
The beauty of using this method more is revealed when using multiple sub-processors.
Here we call the processor that calls other processors (the code that is called processor).
<?

$user = false;
$doc = false;

// Try to create user
$response = $modx- > runProcessor('security/user/create', $scriptProcessor);

// If the error message returned from the executing CPU
if($response->isError()){
return $modx- > error- > failure($response->getMessage());
}
else{
// Otherwise get user
$user = $response->getObject();
}

// If everything is OK, running the processor to create a document
$response = $modx- > runProcessor('assets.doc.create', array(
'parent' => 0,
'pagetitle' => 'Our document'
));

// Again, if the error message returned from the executing CPU
if($response->isError()){
return $modx- > error- > failure($response->getMessage());
}
else{
// Otherwise get the document
$doc = $response->getObject();
}

// If everything is OK, vozvrashaet success
return array(
'success' => true,
'message' => ",
'object' => array(
'user' => $user,
'doc' => $doc,
)
);

/*
Please note that at the end we did not use the $modx->error->success(failure),
and returned an array.
Fundamentally you may be nothing to notice, that is, via $response->getObject() you will get the same object,
but still there is a difference.
Returning $modx- > error- > success(", $object); you cannot return an object. 
The returned object method $modx->error->success will be converted to an array
what the conversion will be done recursively for all levels and keys of different levels will be rewritten,
the result can be a single-level array with data loss.
It is for this despite the fact that the system processor security/user/create return $user->toArray(), namely $user,
the result is not an object $user, namely the array. That is, we will not be able with him to perform the methods of the class modUser type ->toArray()
Returning from the array with the element 'object' can return is the object 
that is, the output to perform the type of $response->getObject()->get('id');
*/

Thus we get a clear result or $response->isError () or not.
However, we do not think about the degree of nesting of these processors, regardless of how many levels of nested processors was not, with proper execution, regardless of what level of nesting, an error will occur we will know about it and get a text message as return $modx- > error- > failure($response->getMessage()); each time will return to the next nested message processor.

It should be noted that all dminskaya part of MODx is written in processors (see the folder /core/model/modx/processors/) and if it is correct to use the processors, many third-party packages might not be necessary.
What could be simpler than $modx- > runSnippet('security/login', $scriptProcessor);?
MODx will perform all the necessary in the case of what will return one of the prescribed in all cases of error messages. In these processors and checking for the right permissions and all the system variables and calls to other connected processors. In General, all you need...

Therefore, we would be under every small action creates the needed processor and to perform more extensive tasks, collect the individual processors in a heap.
First, such a separate processor easier to understand. They clearly understand that what is being done and where the logical conclusion of the task. And perhaps most importantly — less any extra branching if, else, etc., as some of these if-else sometimes reach several hundreds (or even thousands) of lines of code.
Second, the failure of one processor has a much smaller negative impact on the entire site, compared with the output of one large class for code parsing error or something (if of course incomprehensible to normal programmer, but nevertheless it happens).

But another very powerful plus in this approach is standardised responses on the server side, and browser (when using Ajax).
If you send a request to the connector, which will be called the desired processor response is returned in a JSON object, which will be the success and message and object.
This allows you to use the same processors for both server-side logic, and pseudo-client.
If there is interest, learn more about connectors I will write later.
Article based on information from habrahabr.ru

Комментарии

Популярные сообщения из этого блога

March Habrameeting in Kiev

PostgreSQL load testing using JMeter, Yandex.Tank and Overload

Monitoring PostgreSQL with Zabbix