Sedikit pengantar:
Format ocmod adalah solusi yang cukup elegan untuk menentukan modifikasi pada file sumber, apa pun formatnya. Salah satu bagian dari format - itu adalah file XML, yang ditulis, dalam file apa dan di mana file ini diperlukan untuk membuat perubahan tertentu. Berikut adalah contoh file ocmod (diambil dari ocmod.net, penjelasan lebih detail dapat ditemukan di sana):
<?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>
Secara umum, kami menetapkan yang berikut:
<file path=" ">
<operation>
<search><![CDATA[ ]]></search>
<add position=" β , ">
<![CDATA[ ]]>
</add>
</operation>
</file>
Meskipun prinsipnya cukup transparan, pertanyaan yang muncul: apakah mungkin untuk mengotomatiskan proses pembuatannya atau perlu menulisnya dengan tangan, karena programmer harus terlibat dalam pemrograman, dan tidak
Idealnya, menulis modifikasi untuk OpenCart akan terlihat seperti ini: kami mengunduh versi "tak bernoda" dari toko, membuat beberapa perubahan langsung di kode sumbernya dan menjalankan skrip "ajaib" yang menghasilkan seluruh ocmod langsung di tempat. Faktanya, semuanya sedikit lebih rumit, tetapi kami akan mencoba lebih dekat dengan skema ini. Masalah utamanya adalah menentukan lokasi dalam file yang akan disisipkan (apa di antara <search> ... </search>). Programmer harus melakukan ini. Sebagai aturan, cobalah menjadikannya yang paling serbaguna, untuk menjangkau versi sumber yang lebih potensial dan pada saat yang sama memberikan saya tepat di tempat yang diperlukan. Ini jelas buatan tangan. Yang lainnya otomatis.
Penyimpangan kecil: pencarian terjadi di seluruh string, dan penyisipan hanya mungkin dilakukan sebelum, setelah atau sebagai gantinya, tetapi tidak di dalam (dalam paket OCMOD klasik untuk Opencart). Ini adalah batasan yang tidak jelas bagi saya pribadi. Selain itu, saya tidak mengerti mengapa tidak mungkin menyetel beberapa tag <search> untuk menemukan titik penyisipan yang diinginkan, yang akan diproses secara konsisten - lagipula, pencarian akan jauh lebih fleksibel. Misalnya, jika dalam kode PHP, katakanlah, temukan nama fungsinya, lalu temukan tempat yang tepat di dalamnya, atau entah bagaimana menurut kebijaksanaan programmer. Tetapi saya tidak menemukan ini, jika saya salah, tolong perbaiki.
Dan sekarang yang paling penting: Anda dapat mengotomatiskan proses pembuatan file ocmod, dan Anda hanya perlu mengikuti skema yang diinginkan. Pertama, di file sumber, kita perlu menunjukkan tempat perubahan kita - keduanya hanya untuk pesanan, dan agar generator ocmod kita mengetahui semuanya dengan tepat. Misalkan nama kita adalah Pyotr Nikolaevich Ivanov (kebetulan acak). Mari kita lampirkan semua perubahan kita di antara tag <PNI> ... </PNI>, dan agar tag tersebut tidak merusak sumber, kami akan menempatkan tag ini di komentar bahasa yang sedang kami kerjakan. Di antara tag, tepat di tempatnya, kita akan menyetel string pencarian antara <search> </search> dan kode yang ditambahkan antara <add> </add>. Ini akan lebih jelas dengan contoh:
Untuk perubahan di PHP:
β¦
( opencart)
β¦
// <PNI>
// -
// , ( )
// <search> public function index() {</search>
// <add position=βafterβ>
$x = 5;
$y = 6;
//</add> </PNI>
β¦
Atau seperti ini:
β¦
( opencart)
β¦
/* <PNI>
<search> public function index() {</search>
<add position=βafterβ> */
$x = 5;
$y = 6;
/*</add> </PNI> */
β¦
Jika <search> atau <add> memiliki atribut apa pun, misalnya, <search index = β1β>, maka atribut tersebut akan ditransfer βsebagaimana adanyaβ ke file ocmod kami. Apa yang kami tulis di antaranya tidak memerlukan pelolosan XML, kami hanya menulis string dan kode pencarian.
Contoh lain, sudah untuk file twig yang kita modifikasi:
{# <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> #}
Setelah kita menata semua perubahan kita dengan cara ini, kita membutuhkan skrip yang akan menangani semua ini, serta pengarsip. Saya berbagi dengan Anda versi saya: ini terdiri dari file konfigurasi dan skrip itu sendiri.
File konfigurasi make-ocmod.opencart.local.cfg.php (encoding UTF-8, ini adalah contoh, semua orang melakukannya sendiri):
<?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 = "";
?>
Sekarang yang utama adalah generator file ocmod xml.
Skrip make-ocmod.php (encoding UTF-8):
<?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);
}
?>
Baris perintah make-ocmod.cmd yang menjalankan semua ini:
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 *.*
Saya menggunakan 7zip, jadi 7z.exe harus berada di tempat yang sama dengan baris perintah kami. Siapa pun yang ingin menggunakannya dapat mengunduhnya dari https://www.7-zip.org/ .
Ini adalah manajer perintah untuk Windows. Siapa di Linux, saya pikir, akan menulis ulang tanpa masalah.
Ringkasan: Menurut pendapat saya, jauh lebih mudah untuk bekerja dengan cara ini daripada mengedit ocmod secara manual setiap saat. Ketika kami menambahkan kode, kami menetapkan tag pencarian kami untuk bagian kode ini tepat di tempat, dan kemudian kami hanya fokus pada pekerjaan kami. Kami tidak lagi peduli tentang struktur file xml, dan kami melakukan koreksi apa pun terhadap modifikasi kami di tempat, segera periksa kerjanya dan kemudian buat file ocmod baru dengan satu klik.