📜 ⬆️ ⬇️

Paradigm programming processors in MODx Revolution

At once I will make a reservation that this article is reasoning and food for thought. I absolutely do not want to arrange holivars and impose my own programming methods on others. I am just telling you, because by my own I feel that the programming methods I have used have changed a lot over the last year and are completely different from the methods of the previous few years.

In this article I would like to tell how MODx Revolution as a whole changed my approach to programming.
I don’t know how anyone programs, but I believe that I’m already programming OOP methods a long time ago. Why was programming in general reduced? I wrote (or took ready) classes for my tasks (a class for working with a database, a class for working with templates, a class for something else). Most of the classes were quite large and carried out many necessary tasks in their profile. Most of the time as the project grew, many classes grew, or acquired extensions, or both. One way or another, I am sure many people have come across a situation of hourly parsing an object in a couple of thousand lines and several dozens of methods in order to figure out where you can make the next changes, but in such a way that something else does not break. But in my opinion the most difficult thing is to ensure the harmonious interaction of various objects among themselves, especially in terms of intercepting errors while performing certain actions, and most importantly at the time of an error, decide how critical it is and whether it is worth interrupting the execution process, or you can go further. And also to assign client-server solutions here, in order to standardize execution responses for the server part (with its further rendering into templates) and for Ajax requests.

What tools does MODx Revolution propose for programming project logic? There are only two classes: Processor (performed by the modProcessor class) and Connector (performed by the modConnector class).
What it is? Processor - a separate file with most often one or several small tasks, as a result of which the answer should only be positive (which will indicate a positive result of the execution), or negative (preferably with a specific error message), which will by itself say that something critically wrong has happened.
')
I will give a small example. We want to create a new document. If the document is created, then great, if not, we need to get an error message.

1. Create a folder of our processors in core / model / modx / processors /, let's call it, for example, assets /
2. Create a file processor doc / create.php (the full path will be core / model / modx / processors / assets / doc / create.php)
3. Write the code we need in it.
<? if(!$scriptProperties['pagetitle']){ return $modx->error->failure('    '); } if(!isset($scriptProperties['parent'])){ return $modx->error->failure('     '); } $doc = $modx->newObject('modResource', scriptProperties); if(!$doc->save()){ return $modx->error->failure('   '); } return $modx->error->success('  ', $doc->toArray()); 


4. And now in the right place we call this processor
 $response = $modx->runProcessor('assets.doc.create', array( 'parent' => 0, 'pagetitle' => ' ' )); if($response->isError()){ print " ". $response->getMessage(); } else{ $object = $response->getObject(); print "    ID {$object['id']}"; } /*$modx->runProcessor -   MODx.   .php     ,       create.php  -  .      assets.doc.create   ,       assets/doc/         core/model/modx/processors/       ,       $modx->runProcessor($path, $properties, array( processors_path => self::$processorsPath));    $properties -  ,          scriptProperties.       .       $modx,            . */ 


This is a particular example and does not reveal even approximately what I wanted to say.
The beauty of using this method is revealed more when using several nested processors at once.
Here we call the processor, in which other processors are called (the code of the called processor is given).
 <? $user = false; $doc = false; //    $response = $modx->runProcessor('security/user/create', $scriptProcessor); //  ,      if($response->isError()){ return $modx->error->failure($response->getMessage()); } else{ //    $user = $response->getObject(); } //   ,      $response = $modx->runProcessor('assets.doc.create', array( 'parent' => 0, 'pagetitle' => ' ' )); // -,  ,      if($response->isError()){ return $modx->error->failure($response->getMessage()); } else{ //    $doc = $response->getObject(); } //   ,   return array( 'success' => true, 'message' => '', 'object' => array( 'user' => $user, 'doc' => $doc, ) ); /*  ,        $modx->error->success(failure),    .         ,    $response->getObject()      ,     .  $modx->error->success('', $object);    .    $modx->error->success    ,               ,          .       ,    security/user/create   $user->toArray(),   $user,       $user,   .           modUser  ->toArray()      'object',    ,       $response->getObject()->get('id'); */ 

Thus at the output we get a clear result, or $ response-> isError (), or not.
At the same time, we do not think about the degree of nesting of these processors, no matter how many levels of nesting of processors there are, with proper organization of execution, regardless of at what level of nesting an error occurs, we will know about it and display a text message, since return $ modx- > error-> failure ($ response-> getMessage ()); each time will return the message of the next embedded processor.

It should be noted that the entire admin part of MODx is written on processors (see the folder / core / model / modx / processors /) and if used correctly, many third-party packages may not be needed at all.
What could be simpler than $ modx-> runSnippet ('security / login', $ scriptProcessor) ;?
MODx will do everything necessary and in which case it will return one of the error messages written for all cases. In these processors, and checks on access rights, and any system variables, and calls to other related processors. In general, all you need ...

Thus, as if for each small action we create the processor we need and for performing more extensive tasks we collect individual processors in a heap.
First, such separate processors are easier to understand. They clearly understand what is being done for what and where the logical conclusion of the task is. And probably the most important thing is that there are fewer if any extra branches if, else, etc., since some of these if-else sometimes reach several hundred (or even thousand) lines of code.
Secondly, the failure of a single processor has a much smaller negative impact on the operation of the entire site, compared to the output of one large class due to an error parsing the code or something like that (of course not understandable to a normal programmer, but nevertheless anything can happen).
And thirdly, in general, an engine with a similar implementation is serviced much easier and more intuitively.

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

Source: https://habr.com/ru/post/154081/


All Articles