OCmod-Dateigenerator für einen Online-Shop auf Opencart

Ist es realistisch, sich bei der Entwicklung von Änderungen für die beliebte Opencart Online Store Engine auf Ihre Algorithmen zu konzentrieren und die Vorbereitung einer Datei für das Hochladen auf dieses CMS speziellen Skripten zu überlassen? Dies würde den Entwicklern unter Opencart das Leben erheblich erleichtern, und in diesem Artikel biete ich meine Lösung an.



Eine kleine Einführung:



Das ocmod-Format ist eine ziemlich elegante Lösung zum Definieren von Änderungen an Quelldateien, unabhängig von deren Format. Einer der Teile des Formats ist eine XML-Datei, die angibt, in welcher Datei und wo in dieser Datei bestimmte Änderungen vorgenommen werden müssen. Hier ist ein Beispiel für eine ocmod-Datei (aus ocmod.net entnommen, eine ausführlichere Beschreibung finden Sie dort):



<?xml version="1.0" encoding="utf-8"?>
<modification>
    <name>   </name>
    <code>product-page-views</code>
    <version>1.0</version>
    <author>https://ocmod.net</author>
    <link>https://ocmod.net</link>
    <file path="catalog/controller/product/product.php">
        <operation>
            <search>
                <![CDATA[$data['images'] = array();]]>
            </search>
            <add position="after">
                <![CDATA[
                	$data['view'] = $product_info['viewed'];
                ]]>
            </add>
        </operation>
    </file>
    <file path="catalog/language/en-gb/product/product.php">
        <operation>
            <search>
                <![CDATA[$_['text_search']]]>
            </search>
            <add position="before">
                <![CDATA[
                	$_['text_view']              = 'View: ';
                ]]>
            </add>
        </operation>
    </file>
</modification>


Im Allgemeinen legen wir Folgendes fest:



<file path="  ">
        <operation>
            <search><![CDATA[ ]]></search>
            <add position=" – ,   ">
                <![CDATA[    ]]>
            </add>
        </operation>
    </file>


Obwohl das Prinzip ziemlich transparent ist, stellt sich die Frage: Ist es möglich, den Prozess seiner Erstellung zu automatisieren, oder muss es von Hand geschrieben werden, da der Programmierer mit der Programmierung beschäftigt sein sollte und nicht mit albernen Routinetätigkeiten masturbieren sollte .



Im Idealfall würde das Schreiben einer Modifikation für Opencart folgendermaßen aussehen: Wir haben die "makellose" Version des Stores heruntergeladen, einige Änderungen direkt am Quellcode vorgenommen und ein "magisches" Skript ausgeführt, das den gesamten ocmod direkt vor Ort generiert. Tatsächlich ist alles etwas komplizierter, aber wir werden versuchen, diesem Schema näher zu kommen. Das Hauptproblem besteht darin, den Speicherort in der einzufügenden Datei zu bestimmen (was zwischen <search> ... </ search> liegt). Der Programmierer muss dies tun. In der Regel versuchen sie, es so universell wie möglich zu gestalten, um mehr potenzielle Versionen der Quelle abzudecken, und gleichzeitig, damit es sich genau dort ändert, wo es benötigt wird. Dies ist eindeutig handgemacht. Alles andere ist automatisiert.



Ein kleiner Exkurs: Die Suche erfolgt in der gesamten Zeichenfolge, und das Einfügen ist nur davor, danach oder stattdessen möglich, jedoch nicht innerhalb (im klassischen OCMOD-Paket für Opencart). Dies ist eine Einschränkung, die für mich persönlich unverständlich ist. Ich verstehe auch nicht, warum es unmöglich ist, mehrere <search> -Tags zu setzen, um die gewünschte Einfügemarke zu finden, die konsistent verarbeitet wird - schließlich wäre die Suche viel flexibler. Wenn Sie beispielsweise im PHP-Code beispielsweise den Namen der Funktion suchen, dann die richtige Stelle darin finden oder nach Ermessen des Programmierers. Aber ich habe das nicht gefunden. Wenn ich mich irre, korrigieren Sie es bitte.



Und jetzt das Wichtigste: Sie können den Prozess der Erstellung einer ocmod-Datei automatisieren und müssen nur das gewünschte Schema einhalten. Zuerst müssen wir in der Quelldatei irgendwie den Ort unserer Änderungen angeben - sowohl nur zur Bestellung als auch damit unser ocmod-Generator alles adressierbar weiß. Nehmen wir an, unser Name ist Peter Nikolaevich Ivanov (Zufälle sind zufällig). Lassen Sie uns alle unsere Änderungen zwischen den Tags <PNI> ... </ PNI> einschließen. Damit die Tags die Quelle nicht verderben, werden diese Tags in die Kommentare der Sprache eingefügt, an der wir gerade arbeiten. Zwischen den Tags setzen wir die Suchzeichenfolge zwischen <search> </ search> und den hinzugefügten Code zwischen <add> </ add>. Anhand eines Beispiels wird es klarer:



Für Änderungen in PHP:




(   opencart)
// <PNI>
//             -
//      ,    (   )
// <search> public function index() {</search>
// <add position=”after”>
$x = 5;
$y = 6;
//</add> </PNI>


Oder so:




(   opencart)
/* <PNI>
     <search> public function index() {</search>
     <add position=”after”> */
$x = 5;
$y = 6;
/*</add> </PNI> */


Wenn <search> oder <add> Attribute hat, z. B. <search index = ”1”>, werden diese unverändert in unsere ocmod-Datei übertragen. Was wir dazwischen schreiben, erfordert kein XML-Escape, wir schreiben nur die Suchzeichenfolge und den Code.



Ein weiteres Beispiel, das wir bereits für die Zweigdatei ändern:



            {# <PNI>
            <search><li><span style="text-decoration: line-through;">{{ price }}</span></li></search>
            <add position="replace">
            #}
            <li><span class="combination-base-price" style="text-decoration: line-through;">{{ price }}</span></li>
            {# </add></PNI> #}


Nachdem wir alle unsere Änderungen auf diese Weise formalisiert haben, benötigen wir ein Skript, das all dies behandelt, sowie einen Archivierer. Ich teile Ihnen meine Version mit: Sie besteht aus einer Konfigurationsdatei und einem Skript selbst.



Die Konfigurationsdatei make-ocmod.opencart.local.cfg.php (UTF-8-Codierung, dies ist ein Beispiel, jeder macht es für sich selbst):



<?php

define("ROOT_PATH", "../../opencart.local");

define("ENCODING", "utf-8");
define("NAME", " ocmod");
define("CODE", "product-page-views");
define("VERSION", "1.0");
define("AUTHOR", "AS");
define("LINK", "");

define("TAG_OPERATION_BEGIN", "<PNI>");
define("TAG_OPERATION_END", "</PNI>");
define("TAG_SEARCH_BEGIN", "<search"); // !!  >
define("TAG_SEARCH_END", "</search>");
define("TAG_ADD_BEGIN", "<add"); // !!  >
define("TAG_ADD_END", "</add>");

//     </add>      
// ( ,   , ).
//    ,   , 
//   </add> ( , \t, \r, \n  ,  )
$commentsBegin = [ '//', '/*', '<!--', '{#' ];
//     <add>      
// ( ,   , ).
//    ,   , 
//   <add> ( , \t, \r, \n  ,  )
$commentsEnd = [ '*/', '-->', '#}' ];

//       ,     
//  .
$exclude = [ '/cache/', '/cache-/' ];

//      upload.
//     ,   .
$upload = [
  'admin/view/stylesheet/combined-options.css',
  'admin/view/javascript/combined-options.js',
  'catalog/view/theme/default/stylesheet/combined-options.css',
  'admin/view/image/combined-options/cross.png',
  'catalog/view/javascript/combined-options/combined.js',
  'catalog/view/javascript/combined-options/aswmultiselect.js',
  'admin/view/image/combined-options/select.png'
];

//     install.sql.
// (   Opencart  )
$sql = "";

?>


Jetzt ist die Hauptsache der ocmod xml-Dateigenerator.

Make-ocmod.php-Skript (UTF-8-Codierung):



<?php

include_once ($argv[1]);

function processFile($fileName, $relativePath) {
  global $commentsBegin, $commentsEnd, $xml, $exclude;

  if ($exclude)
    foreach ($exclude as $ex)
      if (false !== strpos($relativePath, $ex))
        return;

  $text = file_get_contents($fileName);
  $end = -1;
  while (false !== ($begin = strpos($text, TAG_OPERATION_BEGIN, $end + 1))) {
    $end = strpos($text, TAG_OPERATION_END, $begin + 1);
    if (false === $end)
      die ("No close operation tag in ".$fileName);
    $search = false;
    $searchEnd = $begin;
    while (false !== ($searchBegin = strpos($text, TAG_SEARCH_BEGIN, $searchEnd + 1)) and $searchBegin < $end) {
      $searchBeginR = strpos($text, '>', $searchBegin + 1);
      $searchAttributes = substr($text, $searchBegin + strlen(TAG_SEARCH_BEGIN), $searchBeginR - $searchBegin - strlen(TAG_SEARCH_BEGIN));
      if (false === $searchBeginR or $searchBeginR >= $end)
        die ("Invalid search tag in ".$fileName);
      $searchEnd = strpos($text, TAG_SEARCH_END, $searchBeginR + 1);
      if (false === $searchEnd or $searchEnd >= $end)
        die ("No close search tag in ".$fileName);
      //  
      $search = substr($text, $searchBeginR + 1, $searchEnd - $searchBeginR - 1);
    }
    $addBegin = strpos($text, TAG_ADD_BEGIN, $begin + 1);
    if (false === $addBegin or $addBegin >= $end)
      die ("No begin add tag in ".$fileName);
    $addBeginR = strpos($text, '>', $addBegin + 1);
    $addAttributes = substr($text, $addBegin + strlen(TAG_ADD_BEGIN), $addBeginR - $addBegin - strlen(TAG_ADD_BEGIN));
    if (false === $addBeginR or $addBeginR >= $end)
      die ("Invalid add tag in ".$fileName);
    $addEnd = strpos($text, TAG_ADD_END, $addBeginR + 1);
    if (false === $addEnd or $addEnd >= $end)
      die ("No close add tag in ".$fileName);
    $codeBegin = $addBeginR + 1;
    $codeEnd = $addEnd;
    //       ,
    //    - .        .
    $p = $codeBegin;
    while (@$text[$p] === " " or @$text[$p] === "\t" or @$text[$p] === "\r" or @$text[$p] === "\n")
      $p ++;
    if ($p < $addEnd) {
      foreach ($commentsEnd as $tag)
        if (substr($text, $p, strlen($tag)) === $tag)
          $codeBegin = $p + strlen($tag);
    }
    $p = $codeEnd - 1;
    while (@$text[$p] === " " or @$text[$p] === "\t" or @$text[$p] === "\r" or @$text[$p] === "\n")
      $p --;
    if ($p >= $codeBegin) {
      foreach ($commentsBegin as $tag)
        if (substr($text, $p - strlen($tag) + 1, strlen($tag)) === $tag)
          $codeEnd = $p - strlen($tag) + 1;
    }
    $code = substr($text, $codeBegin, $codeEnd - $codeBegin - 1);

    $xml .= "
    <file path=\"".str_replace('"', '\"', $relativePath)."\">
        <operation>".(false !== $search ? "
            <search{$searchAttributes}>
                <![CDATA[{$search}]]>
            </search>" : "")."
            <add{$addAttributes}>
                <![CDATA[{$code}]]>
            </add>
        </operation>
    </file>";
  }
}

function processDir($dir, $relativePath = '') {
  global $exclude;

  $cdir = scandir($dir);
  foreach ($cdir as $key => $value) {
    if (!in_array($value,array(".", ".."))) {
      $fileName = $dir . DIRECTORY_SEPARATOR . $value;
      $newRelativePath = ($relativePath ? $relativePath.'/' : '').$value;
      $excluded = false;
      if ($exclude)
        foreach ($exclude as $ex)
          $excluded = $excluded or false !== strpos($newRelativePath, $ex);
      if ($excluded)
        continue;
      if (is_dir($fileName)) {
        processDir($fileName, $newRelativePath);
      } else {
        processFile($fileName, $newRelativePath);
      }
    }
  }
}

function delTree($dir, $delRoot = false) {
  $files = array_diff(scandir($dir), array('.','..'));
  foreach ($files as $file) {
    (is_dir("$dir/$file")) ? delTree("$dir/$file", true) : unlink("$dir/$file");
  }
  return $delRoot ? rmdir($dir) : true;
}

$xml = "<?xml version=\"1.0\" encoding=\"".ENCODING."\"?>
<modification>
    <name>".NAME."</name>
    <code>".CODE."</code>
    <version>".VERSION."</version>
    <author>".AUTHOR."</author>
    <link>".LINK."</link>";

processDir(ROOT_PATH);

$xml .= "
</modification>";

file_put_contents('publish/install.xml', $xml);
file_put_contents('publish/install.sql', $sql);

delTree('publish/upload');
foreach ($upload as $file) {
  $srcfile = ROOT_PATH.(@$file[0] === '/' ? '' : '/').$file;
  $dstfile = 'publish/upload'.(@$file[0] === '/' ? '' : '/').$file;
  mkdir(dirname($dstfile), 0777, true);
  copy($srcfile, $dstfile);
}

?>


Die Befehlszeile make-ocmod.cmd, mit der all dies ausgeführt wird:



del /f/q/s publish.ocmod.zip
php make-ocmod.php make-ocmod.opencart.local.cfg.php
cd publish
..\7z.exe a -r -tZip ..\publish.ocmod.zip *.*


Ich benutze 7zip, daher sollte sich 7z.exe an derselben Stelle befinden wie unsere Befehlszeile. Wer es verwenden möchte, kann es von https://www.7-zip.org/ herunterladen .



Dies ist ein Befehlsmanager für Windows. Wer unter Linux, denke ich, wird ohne Probleme umschreiben.



Zusammenfassung: Meiner Meinung nach ist es viel einfacher, auf diese Weise zu arbeiten, als ocmod jedes Mal manuell zu bearbeiten. Wenn wir Code hinzufügen, setzen wir unsere Such-Tags für diesen Code direkt vor Ort und konzentrieren uns dann nur auf unsere Arbeit. Wir kümmern uns nicht mehr um die Struktur der XML-Datei und korrigieren unsere Änderungen sofort, überprüfen sofort ihre Arbeit und generieren dann mit einem Klick eine neue ocmod-Datei.



All Articles