简介:
ocmod格式是一种非常优雅的解决方案,用于定义对源文件的修改,而不管其格式如何。格式的一部分是XML文件,在其中写入哪个文件以及在此文件中必须进行某些更改。这是ocmod文件的示例(取自ocmod.net,可以在此处找到更详细的描述):
<?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>
一般而言,我们设置以下内容:
<file path=" ">
<operation>
<search><![CDATA[ ]]></search>
<add position=" – , ">
<![CDATA[ ]]>
</add>
</operation>
</file>
尽管原理很透明,但问题是:可以自动执行其创建过程,还是必须手动编写它,因为程序员应该从事编程工作,而不要
理想情况下,为Opencart编写修改应如下所示:我们下载了商店的“完美无暇”版本,在其源代码中进行了一些更改,并运行了一个“魔术”脚本,当场生成了整个ocmod。实际上,一切都有些复杂,但是我们将尝试更接近该方案。主要问题是确定文件中要插入的位置(<search> ... </ search>之间的位置)。这必须由程序员来完成。通常,他们试图使其尽可能通用,以涵盖源的更多潜在版本,同时使其确切地在需要的地方进行更改。这显然是手工制作的。其他一切都是自动化的。
一个小题外话:搜索发生在整个字符串中,并且只能在插入之前,之后或代替插入,但不能在内部插入(在Opencart的经典OCMOD软件包中)。这是我个人无法理解的限制。而且,我不明白为什么不可能设置几个<search>标签来找到所需的插入点,而插入点将被一致地处理-因为搜索会更加灵活。例如,如果在PHP代码中,则找到函数的名称,然后在函数中找到正确的位置,或者由程序员自行决定以其他方式确定。但是我没有找到这个,如果我弄错了,请更正它。
现在最重要的是:您可以自动化创建ocmod文件的过程,而您只需要遵循所需的方案即可。首先,在源文件中,我们需要以某种方式指出更改的位置-既是为了顺序,又是为了使ocmod生成器可寻址地知道所有内容。假设我们的名字叫Pyotr Nikolaevich Ivanov(巧合是随机的)。让我们将所有更改包含在<PNI> ... </ PNI>标记之间,以使这些标记不会破坏源,我们将这些标记放置在当前正在使用的语言的注释中。在标签之间的正确位置,我们将在<search> </ search>之间设置搜索字符串,并在<add> </ add>之间添加代码。通过一个示例将更加清楚:
对于PHP的更改:
…
( opencart)
…
// <PNI>
// -
// , ( )
// <search> public function index() {</search>
// <add position=”after”>
$x = 5;
$y = 6;
//</add> </PNI>
…
或像这样:
…
( opencart)
…
/* <PNI>
<search> public function index() {</search>
<add position=”after”> */
$x = 5;
$y = 6;
/*</add> </PNI> */
…
如果<search>或<add>具有任何属性,例如<search index =“ 1”>,则它们将“按原样”传输到我们的ocmod文件中。我们之间编写的内容不需要任何XML转义,我们只需编写搜索字符串和代码。
另一个示例,已经针对我们正在修改的树枝文件:
{# <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> #}
在以这种方式设置所有更改的样式之后,我们需要一个可以处理所有这些的脚本以及一个存档器。我正在与您分享我的版本:它包含一个配置文件和一个脚本本身。
配置文件make-ocmod.opencart.local.cfg.php(UTF-8编码,这是一个示例,每个人都自己做):
<?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 = "";
?>
现在最主要的是ocmod xml文件生成器。
Make-ocmod.php脚本(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);
}
?>
运行所有这些的make-ocmod.cmd命令行:
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 *.*
我使用7zip,因此7z.exe应该与我们的命令行位于同一位置。想要使用它的人可以从https://www.7-zip.org/下载。
这是Windows的命令管理器。我认为Linux上的谁会重写而不会出现问题。
简介:我认为,这种方法比每次手动编辑ocmod都容易得多。添加代码时,我们立即在该代码段中设置了搜索标签,然后仅关注工作。我们不再关心xml文件的结构,并且当场对我们的修改进行了任何更正,立即检查其工作,然后一键生成一个新的ocmod文件。